// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "libcef/browser/alloy/alloy_content_browser_client.h"

#include <algorithm>
#include <tuple>
#include <utility>

#include "include/cef_version.h"
#include "libcef/browser/alloy/alloy_browser_context.h"
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/alloy/alloy_browser_main.h"
#include "libcef/browser/alloy/alloy_web_contents_view_delegate.h"
#include "libcef/browser/browser_context.h"
#include "libcef/browser/browser_frame.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/browser_manager.h"
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/certificate_query.h"
#include "libcef/browser/context.h"
#include "libcef/browser/devtools/devtools_manager_delegate.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/extensions/extension_web_contents_observer.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/net/chrome_scheme_handler.h"
#include "libcef/browser/net/throttle_handler.h"
#include "libcef/browser/net_service/cookie_manager_impl.h"
#include "libcef/browser/net_service/login_delegate.h"
#include "libcef/browser/net_service/proxy_url_loader_factory.h"
#include "libcef/browser/net_service/resource_request_handler_wrapper.h"
#include "libcef/browser/prefs/renderer_prefs.h"
#include "libcef/browser/speech_recognition_manager_delegate.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/x509_certificate_impl.h"
#include "libcef/common/alloy/alloy_content_client.h"
#include "libcef/common/app_manager.h"
#include "libcef/common/cef_switches.h"
#include "libcef/common/command_line_impl.h"
#include "libcef/common/extensions/extensions_util.h"
#include "libcef/common/frame_util.h"
#include "libcef/common/net/scheme_registration.h"
#include "libcef/common/request_impl.h"

#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/threading/thread_restrictions.h"
#include "cef/grit/cef_resources.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h"
#include "chrome/browser/net/profile_network_context_service.h"
#include "chrome/browser/net/profile_network_context_service_factory.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/pdf/chrome_pdf_stream_delegate.h"
#include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h"
#include "chrome/browser/plugins/plugin_info_host_impl.h"
#include "chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h"
#include "chrome/browser/plugins/plugin_utils.h"
#include "chrome/browser/predictors/network_hints_handler_impl.h"
#include "chrome/browser/printing/print_view_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/renderer_updater.h"
#include "chrome/browser/profiles/renderer_updater_factory.h"
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/google_url_loader_throttle.h"
#include "chrome/common/pdf_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/browser_resources.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/services/printing/printing_service.h"
#include "chrome/services/speech/buildflags/buildflags.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/embedder_support/switches.h"
#include "components/embedder_support/user_agent_utils.h"
#include "components/pdf/browser/pdf_navigation_throttle.h"
#include "components/pdf/browser/pdf_url_loader_request_interceptor.h"
#include "components/pdf/browser/pdf_web_contents_helper.h"
#include "components/pdf/common/internal_plugin_helpers.h"
#include "components/performance_manager/embedder/binders.h"
#include "components/performance_manager/public/mojom/coordination_unit.mojom.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/site_isolation/site_isolation_policy.h"
#include "components/spellcheck/common/spellcheck.mojom.h"
#include "components/version_info/version_info.h"
#include "content/browser/plugin_service_impl.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/overlay_window.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_ui_url_loader_factory.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/user_agent.h"
#include "crypto/crypto_buildflags.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/extension_protocols.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_web_contents_observer.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/guest_view/extensions_guest_view.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "extensions/browser/process_map.h"
#include "extensions/browser/renderer_startup_helper.h"
#include "extensions/browser/url_loader_factory_manager.h"
#include "extensions/common/constants.h"
#include "extensions/common/switches.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
#include "net/base/auth.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_private_key.h"
#include "pdf/pdf_features.h"
#include "ppapi/host/ppapi_host.h"
#include "sandbox/policy/switches.h"
#include "services/network/public/cpp/network_switches.h"
#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
#include "services/service_manager/public/mojom/connector.mojom.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/mojom/badging/badging.mojom.h"
#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
#include "third_party/blink/public/web/web_window_features.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_MAC)
#include "net/ssl/client_cert_store_mac.h"
#include "services/video_capture/public/mojom/constants.mojom.h"
#elif BUILDFLAG(IS_POSIX)
#include "components/crash/core/app/crash_switches.h"
#include "components/crash/core/app/crashpad.h"
#include "content/public/common/content_descriptors.h"
#include "libcef/common/crash_reporting.h"
#endif

#if BUILDFLAG(IS_WIN)
#if BUILDFLAG(ENABLE_SPEECH_SERVICE)
#include "media/mojo/mojom/renderer_extensions.mojom.h"
#endif
#include "net/ssl/client_cert_store_win.h"
#include "sandbox/win/src/sandbox_policy.h"
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(USE_NSS_CERTS)
#include "net/ssl/client_cert_store_nss.h"
#endif

#if BUILDFLAG(HAS_SPELLCHECK_PANEL)
#include "chrome/browser/spellchecker/spell_check_panel_host_impl.h"
#endif

#if BUILDFLAG(IS_OHOS)
#include <vector>
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/timer/timer.h"
#include "base/ohos/sys_info_utils.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "content/public/browser/file_url_loader.h"
#include "content/public/browser/shared_cors_origin_access_list.h"
#include "libcef/browser/alloy/alloy_client_cert_identity.h"
#include "libcef/browser/alloy/alloy_client_cert_lookup_table.h"
#include "libcef/browser/alloy/alloy_ssl_platform_key.h"
#include "libcef/browser/net_service/restrict_cookie_manager.h"
#include "libcef/browser/printing/ohos_print_manager.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "libcef/browser/report_manager.h"
#endif

#ifdef OHOS_NETWORK_PROXY
#include "net/proxy_resolution/proxy_config_service_ohos.h"
#include "net/proxy_resolution/proxy_resolution_service.h"
#endif

#ifdef OHOS_CA
#include "libcef/browser/alloy/alloy_ssl_platform_key_ohos.h"

constexpr int32_t APPLICATION_API_10 = 10;
#endif

#ifdef OHOS_EDM_POLICY
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "components/content_settings/core/browser/local_network_settings.h"
#endif // #ifdef OHOS_EDM_POLICY

#ifdef OHOS_FCP
#include "components/page_load_metrics/browser/metrics_navigation_throttle.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/page_load_metrics/browser/page_load_metrics_embedder_base.h"
#include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h"
#include "libcef/browser/page_load_metrics/page_load_metrics_initialize.h"
#endif

#if OHOS_URL_TRUST_LIST
#include "libcef/browser/ohos_safe_browsing/ohos_url_trust_list_navigation_throttle.h"
#endif

#if defined(OHOS_EX_PASSWORD) || defined(OHOS_PASSWORD_AUTOFILL)
#include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
#endif //OHOS_EX_PASSWORD

#if defined(OHOS_NO_STATE_PREFETCH)
#include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h"
#include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_processor_impl_delegate.h"
#include "chrome/browser/preloading/prefetch/no_state_prefetch/no_state_prefetch_manager_factory.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_contents.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_processor_impl.h"
#include "components/no_state_prefetch/common/prerender_url_loader_throttle.h"
#include "libcef/browser/predictors/loading_predictor.h"
#include "libcef/browser/predictors/loading_predictor_factory.h"
#include "libcef/browser/predictors/predictor_database.h"
#endif  // defined(OHOS_NO_STATE_PREFETCH)

#if defined(OHOS_COOKIE)
#include "libcef/browser/net_service/cookie_manager_ohos_impl.h"
#endif  // defined(OHOS_COOKIE)

#if defined(OHOS_ARKWEB_EXTENSIONS)
#include "chrome/browser/extensions/chrome_extension_cookies.h"
#include "chrome/browser/extensions/user_script_listener.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
#include "chrome/common/url_constants.h"
#include "components/embedder_support/content_settings_utils.h"
#include "content/public/browser/allow_service_worker_result.h"
#include "content/public/browser/site_isolation_policy.h"
#include "extensions/browser/api/web_request/web_request_api.h"
#include "extensions/browser/api/web_request/web_request_proxying_webtransport.h"
#include "extensions/browser/extension_navigation_throttle.h"
#include "extensions/browser/extension_util.h"
#include "extensions/browser/service_worker/service_worker_host.h"
#include "services/network/public/cpp/self_deleting_url_loader_factory.h"
#include "services/network/public/mojom/web_transport.mojom.h"
#endif

#if defined(OHOS_ARKWEB_EXTENSIONS)
using extensions::APIPermission;
using extensions::ChromeContentBrowserClientExtensionsPart;
using extensions::Extension;
using extensions::Manifest;
using extensions::mojom::APIPermissionID;
#endif

#if defined(OHOS_INCOGNITO_MODE)
#include "libcef/browser/alloy/alloy_off_the_record_browser_context.h"
#endif

#include "components/security_interstitials/content/security_interstitial_tab_helper.h"

#if defined(OHOS_CRASHPAD)
#include "components/crash/content/browser/crash_handler_host_linux.h"
#endif

#if BUILDFLAG(IS_OHOS)
#include "libcef/browser/net/ohos_applink_throttle.h"
#endif

#ifdef OHOS_ARKWEB_ADBLOCK
#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
#include "libcef/browser/subresource_filter/adblock_content_subresource_filter_web_contents_helper_factory.h"
#endif  // OHOS_ARKWEB_ADBLOCK

#ifdef OHOS_CA
#include "third_party/bounds_checking_function/include/securec.h"
#endif  // OHOS_CA

#if defined(OHOS_SITE_ISOLATION)
bool g_siteIsolationMode = false;
#endif
namespace {
#if BUILDFLAG(IS_OHOS)
void TransferVector(const std::vector<std::string>& source,
                    std::vector<CefString>& target) {
  if (!target.empty()) {
    target.clear();
  }

  if (!source.empty()) {
    std::vector<std::string>::const_iterator it = source.begin();
    for (; it != source.end(); ++it) {
      target.push_back(*it);
    }
  }
}
#endif

#if defined(OHOS_CACHE)
constexpr int64_t LARGE_CAPACITY_DEVICE_THRESHOLD = static_cast<int64_t>(100) * 1024 * 1024 * 1024;
constexpr int64_t LARGE_CAPACITY_DEVICE_CACHE_SIZE = 100 * 1024 * 1024;
constexpr int64_t SMALL_CAPACITY_DEVICE_CACHE_SIZE = 20 * 1024 * 1024;
constexpr char WEB_CACHE_PATH[] = "/data/storage/e12/base/cache/web";
#endif // defined(OHOS_CACHE)

#if defined(OHOS_ARKWEB_EXTENSIONS)
// The SpecialAccessFileURLLoaderFactory provided to the extension background
// pages.  Checks with the ChildProcessSecurityPolicy to validate the file
// access.
class SpecialAccessFileURLLoaderFactory
    : public network::SelfDeletingURLLoaderFactory {
 public:
  // Returns mojo::PendingRemote to a newly constructed
  // SpecialAccessFileURLLoaderFactory.  The factory is self-owned - it will
  // delete itself once there are no more receivers (including the receiver
  // associated with the returned mojo::PendingRemote and the receivers bound by
  // the Clone method).
  static mojo::PendingRemote<network::mojom::URLLoaderFactory> Create(
      int child_id) {
    mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote;

    // The SpecialAccessFileURLLoaderFactory will delete itself when there are
    // no more receivers - see the
    // network::SelfDeletingURLLoaderFactory::OnDisconnect method.
    new SpecialAccessFileURLLoaderFactory(
        child_id, pending_remote.InitWithNewPipeAndPassReceiver());

    return pending_remote;
  }

  SpecialAccessFileURLLoaderFactory(const SpecialAccessFileURLLoaderFactory&) =
      delete;
  SpecialAccessFileURLLoaderFactory& operator=(
      const SpecialAccessFileURLLoaderFactory&) = delete;

 private:
  explicit SpecialAccessFileURLLoaderFactory(
      int child_id,
      mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver)
      : network::SelfDeletingURLLoaderFactory(std::move(factory_receiver)),
        child_id_(child_id) {}

  // network::mojom::URLLoaderFactory:
  void CreateLoaderAndStart(
      mojo::PendingReceiver<network::mojom::URLLoader> loader,
      int32_t request_id,
      uint32_t options,
      const network::ResourceRequest& request,
      mojo::PendingRemote<network::mojom::URLLoaderClient> client,
      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
      override {
    if (!content::ChildProcessSecurityPolicy::GetInstance()->CanRequestURL(
            child_id_, request.url)) {
      mojo::Remote<network::mojom::URLLoaderClient>(std::move(client))
          ->OnComplete(
              network::URLLoaderCompletionStatus(net::ERR_ACCESS_DENIED));
      return;
    }
    content::CreateFileURLLoaderBypassingSecurityChecks(
        request, std::move(loader), std::move(client),
        /*observer=*/nullptr,
        /* allow_directory_listing */ true);
  }

  int child_id_;
};

void InitializeFileURLLoaderFactoryForExtension(
    int render_process_id,
    content::BrowserContext* browser_context,
    const extensions::Extension* extension,
    AlloyContentBrowserClient::NonNetworkURLLoaderFactoryMap* factories) {
  // Extensions with the necessary permissions get access to file:// URLs that
  // gets approval from ChildProcessSecurityPolicy. Keep this logic in sync with
  // ExtensionWebContentsObserver::RenderFrameCreated.
  Manifest::Type type = extension->GetType();
  if ((type == Manifest::TYPE_EXTENSION ||
       type == Manifest::TYPE_LEGACY_PACKAGED_APP) &&
      extensions::util::AllowFileAccess(extension->id(), browser_context)) {
    factories->emplace(
        url::kFileScheme,
        SpecialAccessFileURLLoaderFactory::Create(render_process_id));
  }
}

void MaybeAddThrottle(
    std::unique_ptr<content::NavigationThrottle> maybe_throttle,
    std::vector<std::unique_ptr<content::NavigationThrottle>>* throttles) {
  if (maybe_throttle) {
    throttles->push_back(std::move(maybe_throttle));
  }
}
#endif

class CefSelectClientCertificateCallbackImpl
    : public CefSelectClientCertificateCallback {
 public:
  explicit CefSelectClientCertificateCallbackImpl(
      std::unique_ptr<content::ClientCertificateDelegate> delegate
#if BUILDFLAG(IS_OHOS)
      ,
      const std::string& host,
      int port
#endif
      )
      : delegate_(std::move(delegate))
#if BUILDFLAG(IS_OHOS)
        ,
        host_(host),
        port_(port)
#endif
  {
  }

  CefSelectClientCertificateCallbackImpl(
      const CefSelectClientCertificateCallbackImpl&) = delete;
  CefSelectClientCertificateCallbackImpl& operator=(
      const CefSelectClientCertificateCallbackImpl&) = delete;

  ~CefSelectClientCertificateCallbackImpl() {
    // If Select has not been called, call it with NULL to continue without any
    // client certificate.
    if (delegate_) {
#if BUILDFLAG(IS_OHOS)
      DoCancel();
#else
      DoSelect(nullptr);
#endif
    }
  }

#if BUILDFLAG(IS_OHOS)
  void Select(const CefString& private_key_file,
              const CefString& cert_chain_file) override {
    if (delegate_) {
      DoSelect(private_key_file, cert_chain_file);
    }
  }

  void Cancel() override {
    if (delegate_) {
      DoCancel();
    }
  }

  void Ignore() override {
    if (delegate_) {
      DoIgnore();
    }
  }
#else
  void Select(CefRefPtr<CefX509Certificate> cert) override {
    if (delegate_) {
      DoSelect(cert);
    }
  }
#endif

 private:
#if !BUILDFLAG(IS_OHOS)
  void DoSelect(CefRefPtr<CefX509Certificate> cert) {
    if (CEF_CURRENTLY_ON_UIT()) {
      RunNow(std::move(delegate_), cert);
    } else {
      CEF_POST_TASK(
          CEF_UIT,
          base::BindOnce(&CefSelectClientCertificateCallbackImpl::RunNow,
                         std::move(delegate_), cert));
    }
  }

  static void RunNow(
      std::unique_ptr<content::ClientCertificateDelegate> delegate,
      CefRefPtr<CefX509Certificate> cert) {
    CEF_REQUIRE_UIT();
    if (cert) {
      CefX509CertificateImpl* certImpl =
          static_cast<CefX509CertificateImpl*>(cert.get());
      certImpl->AcquirePrivateKey(base::BindOnce(
          &CefSelectClientCertificateCallbackImpl::RunWithPrivateKey,
          std::move(delegate), cert));
      return;
    }

    delegate->ContinueWithCertificate(nullptr, nullptr);
  }
#else
  void DoCancel() {
    if (CEF_CURRENTLY_ON_UIT()) {
      RunCancelNow(std::move(delegate_), host_, port_);
    } else {
      CEF_POST_TASK(
          CEF_UIT,
          base::BindOnce(&CefSelectClientCertificateCallbackImpl::RunCancelNow,
                         std::move(delegate_), host_, port_));
    }
  }

  void DoIgnore() {
    if (CEF_CURRENTLY_ON_UIT()) {
      RunIgnoreNow(std::move(delegate_), host_, port_);
    } else {
      CEF_POST_TASK(
          CEF_UIT,
          base::BindOnce(&CefSelectClientCertificateCallbackImpl::RunIgnoreNow,
                         std::move(delegate_), host_, port_));
    }
  }

  void DoSelect(const std::string& private_key_file,
                const std::string& cert_chain_file) {
    if (CEF_CURRENTLY_ON_UIT()) {
      RunSelectNow(std::move(delegate_), private_key_file, cert_chain_file,
                   host_, port_);
    } else {
      CEF_POST_TASK(
          CEF_UIT,
          base::BindOnce(&CefSelectClientCertificateCallbackImpl::RunSelectNow,
                         std::move(delegate_), private_key_file,
                         cert_chain_file, host_, port_));
    }
  }

  static void RunCancelNow(
      std::unique_ptr<content::ClientCertificateDelegate> delegate,
      const std::string& host,
      int port) {
    LOG(INFO) << "CefSelectClientCertificateCallbackImpl::RunCancelNow";
    CEF_REQUIRE_UIT();
    AlloyClientCertLookupTable::Deny(host, port);
    delegate->ContinueWithCertificate(nullptr, nullptr);
  }

  static void RunIgnoreNow(
      std::unique_ptr<content::ClientCertificateDelegate> delegate,
      const std::string& host,
      int port) {
    LOG(INFO) << "CefSelectClientCertificateCallbackImpl::RunIgnoreNow";
    CEF_REQUIRE_UIT();
    delegate->ContinueWithCertificate(nullptr, nullptr);
  }

  static scoped_refptr<net::SSLPrivateKey> WrapOpenSSLPrivateKey(
      bssl::UniquePtr<EVP_PKEY> key) {
    if (!key) {
      return nullptr;
    }

    return base::MakeRefCounted<net::ThreadedSSLPrivateKey>(
        std::make_unique<SSLPlatformKey>(std::move(key)),
        net::GetSSLPlatformKeyTaskRunner());
  }

  static net::ClientCertIdentityList ClientCertIdentityListFromCertificateList(
      const net::CertificateList& certs) {
    net::ClientCertIdentityList result;
    for (const auto& cert : certs) {
      result.push_back(std::make_unique<ClientCertIdentityOhos>(cert, nullptr));
    }

    return result;
  }

  static void AcquirePrivateKey(
      std::unique_ptr<content::ClientCertificateDelegate> delegate,
      CefRefPtr<CefX509Certificate> cert,
      const std::string& private_key_file,
      std::string& pkcs8) {
#ifdef OHOS_CA
    scoped_refptr<net::SSLPrivateKey> ssl_private_key = nullptr;
    if (GetApplicationApiVersion() < APPLICATION_API_10) {
      CBS cbs;
      CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()),
               pkcs8.size());
      bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs));
      if (!pkey || CBS_len(&cbs) != 0) {
        LOG(ERROR) << "AcquirePrivateKey: EVP parse private key failed, pkey = "
                   << pkey << ", CBS length = " << CBS_len(&cbs);
        return;
      }

      ssl_private_key = WrapOpenSSLPrivateKey(std::move(pkey));
      if (!ssl_private_key) {
        LOG(ERROR) << "AcquirePrivateKey: ssl private key parse failed";
        return;
      }
    } else {
      ssl_private_key = WrapOpenSSLPrivateKeyOHOS(private_key_file);
      if (!ssl_private_key) {
        LOG(ERROR) << "AcquirePrivateKey: ssl private key parse failed";
        return;
      }
    }
#else
    CBS cbs;
    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pkcs8.data()),
             pkcs8.size());
    bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs));
    if (!pkey || CBS_len(&cbs) != 0) {
      LOG(ERROR) << "AcquirePrivateKey: EVP parse private key failed, pkey = "
                 << pkey << ", CBS length = " << CBS_len(&cbs);
      return;
    }

    scoped_refptr<net::SSLPrivateKey> ssl_private_key =
        WrapOpenSSLPrivateKey(std::move(pkey));
    if (!ssl_private_key) {
      LOG(ERROR) << "AcquirePrivateKey: ssl private key parse failed";
      return;
    }
#endif
    RunWithPrivateKey(std::move(delegate), cert, ssl_private_key);
  }

  static void RunSelectNow(
      std::unique_ptr<content::ClientCertificateDelegate> delegate,
      const std::string& private_key_file,
      const std::string& cert_chain_file,
      const std::string& host,
      int port) {
    LOG(INFO) << "CefSelectClientCertificateCallbackImpl::RunSelectNow";
    CEF_REQUIRE_UIT();
#ifdef OHOS_CA
    net::CertificateList certsList;
    if (GetApplicationApiVersion() < APPLICATION_API_10) {
      // Client certificate file read
      std::string cert_data;
      base::FilePath src_root_cert;
      base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root_cert);
      if (!base::ReadFileToString(src_root_cert.AppendASCII(cert_chain_file),
                                  &cert_data)) {
        LOG(ERROR) << "RunSelectNow: read cert file to string failed";
        return;
      }

      // Convert the client certificates file to X509
      certsList = net::X509Certificate::CreateCertificateListFromBytes(
          base::as_bytes(base::make_span(cert_data)),
          net::X509Certificate::FORMAT_AUTO);
      if (certsList.empty()) {
        LOG(ERROR) << "RunSelectNow: certs list is empty";
        return;
      }
    } else {
      // Get client certificate from ohos cert manager
      auto RootCertDataAdapter =
          OHOS::NWeb::OhosAdapterHelper::GetInstance().GetRootCertDataAdapter();
      if (RootCertDataAdapter == nullptr) {
        LOG(ERROR) << "RunSelectNow: root cert data adapter is null";
        return;
      }
      char* uri = new char[private_key_file.length() + 1];
      if (uri == nullptr) {
        LOG(ERROR) << "RunSelectNow: new uri memory failed";
        return;
      }

      uint32_t i = 0;
      for (; i < private_key_file.length(); i++) {
        uri[i] = private_key_file[i];
      }
      uri[i] = '\0';

      auto certMaxSize = RootCertDataAdapter->GetAppCertMaxSize();
      uint8_t* certData = new uint8_t[certMaxSize];
      if (certData == nullptr) {
        LOG(ERROR) << "RunSelectNow: new cert data memory failed";
        delete[] uri;
        return;
      }

      if (memset_s(certData, certMaxSize, 0, certMaxSize) != EOK) {
        return;
      }
      uint32_t len = 0;
      RootCertDataAdapter->GetAppCert((uint8_t*)uri, certData, &len);
      if (len == 0) {
        LOG(ERROR) << "RunSelectNow: get app cert failed";
        delete[] uri;
        delete[] certData;
        return;
      }

      certsList = net::X509Certificate::CreateCertificateListFromBytes(
          base::as_bytes(
              base::make_span(static_cast<const uint8_t*>(certData), len)),
          net::X509Certificate::FORMAT_AUTO);
      if (certsList.empty()) {
        LOG(ERROR) << "RunSelectNow: certs list is empty";
        delete[] uri;
        delete[] certData;
        return;
      }

      delete[] uri;
      delete[] certData;
    }
#else
    // Client certificate file read
    std::string cert_data;
    base::FilePath src_root_cert;
    base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root_cert);
    if (!base::ReadFileToString(src_root_cert.AppendASCII(cert_chain_file),
                                &cert_data)) {
      LOG(ERROR) << "RunSelectNow: read cert file to string failed";
      return;
    }

    // Convert the client certificates file to X509
    net::CertificateList certsList =
        net::X509Certificate::CreateCertificateListFromBytes(
            base::as_bytes(base::make_span(cert_data)),
            net::X509Certificate::FORMAT_AUTO);
    if (certsList.empty()) {
      LOG(ERROR) << "RunSelectNow: certs list is empty";
      return;
    }
#endif

    auto client_certs = ClientCertIdentityListFromCertificateList(certsList);
    CefRequestHandler::X509CertificateList certs;
    for (net::ClientCertIdentityList::iterator iter = client_certs.begin();
         iter != client_certs.end(); iter++) {
      certs.push_back(new CefX509CertificateImpl(std::move(*iter)));
    }

    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
    for (size_t i = 1; i < certsList.size(); ++i) {
      intermediates.push_back(bssl::UpRef(certsList[i]->cert_buffer()));
    }

    scoped_refptr<net::X509Certificate> cert_X509(
        net::X509Certificate::CreateFromBuffer(
            bssl::UpRef(certsList[0]->cert_buffer()),
            std::move(intermediates)));

    // Save the converted X509 format certificate
    CefX509CertificateImpl* certImpl =
        static_cast<CefX509CertificateImpl*>(certs[0].get());
    certImpl->setClientCert(cert_X509);

    // Private key file read
    std::string prikey_data;
#ifdef OHOS_CA
    if (GetApplicationApiVersion() < APPLICATION_API_10) {
      base::FilePath src_root_prikey;
      base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root_prikey);
      if (!base::ReadFileToString(src_root_prikey.AppendASCII(private_key_file),
                                  &prikey_data)) {
        LOG(ERROR) << "RunSelectNow: private key file to string failed";
        return;
      }
    }
#else
    base::FilePath src_root_prikey;
    base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root_prikey);
    if (!base::ReadFileToString(src_root_prikey.AppendASCII(private_key_file),
                                &prikey_data)) {
      LOG(ERROR) << "RunSelectNow: private key file to string failed";
      return;
    }
#endif

    AcquirePrivateKey(std::move(delegate), certs[0], private_key_file,
                      prikey_data);
    return;
  }
#endif

#ifdef OHOS_CA
  static int32_t GetApplicationApiVersion() {
    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
            switches::kOhosAppApiVersion)) {
      LOG(ERROR) << "kOhosAppApiVersion not exist";
      return -1;
    }
    std::string apiVersion =
        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
            switches::kOhosAppApiVersion);
    if (apiVersion.empty()) {
      return -1;
    }
    return std::stoi(apiVersion);
  }

  static scoped_refptr<net::SSLPrivateKey> WrapOpenSSLPrivateKeyOHOS(
      const std::string& private_key_file) {
    if (!private_key_file.c_str()) {
      LOG(ERROR) << "WrapOpenSSLPrivateKey, private key file is null";
      return nullptr;
    }

    return base::MakeRefCounted<net::ThreadedSSLPrivateKey>(
        std::make_unique<SSLPlatformKeyOHOS>(private_key_file),
        net::GetSSLPlatformKeyTaskRunner());
  }
#endif

  static void RunWithPrivateKey(
      std::unique_ptr<content::ClientCertificateDelegate> delegate,
      CefRefPtr<CefX509Certificate> cert,
      scoped_refptr<net::SSLPrivateKey> key) {
    CEF_REQUIRE_UIT();
    DCHECK(cert);

    if (key) {
      CefX509CertificateImpl* certImpl =
          static_cast<CefX509CertificateImpl*>(cert.get());
      delegate->ContinueWithCertificate(certImpl->GetInternalCertObject(), key);
    } else {
      delegate->ContinueWithCertificate(nullptr, nullptr);
    }
  }

  std::unique_ptr<content::ClientCertificateDelegate> delegate_;

#if BUILDFLAG(IS_OHOS)
  std::string host_;
  int port_;
#endif

  IMPLEMENT_REFCOUNTING(CefSelectClientCertificateCallbackImpl);
};

#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
int GetCrashSignalFD() {
  if (!crash_reporting::Enabled()) {
    return -1;
  }

#if defined(OHOS_CRASHPAD)
  // ohos don't use linux crash handler
  int crash_signal_fd = crashpad::CrashHandlerHost::Get()->GetDeathSignalSocket();
  return crash_signal_fd;
#else
  int fd;
  pid_t pid;
  return crash_reporter::GetHandlerSocket(&fd, &pid) ? fd : -1;
#endif
}
#endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)

// From chrome/browser/plugins/chrome_content_browser_client_plugins_part.cc.
void BindPluginInfoHost(
    int render_process_id,
    mojo::PendingAssociatedReceiver<chrome::mojom::PluginInfoHost> receiver) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  content::RenderProcessHost* host =
      content::RenderProcessHost::FromID(render_process_id);
  if (!host) {
    return;
  }

  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
  mojo::MakeSelfOwnedAssociatedReceiver(
      std::make_unique<PluginInfoHostImpl>(render_process_id, profile),
      std::move(receiver));
}

void BindBadgeService(
    content::RenderFrameHost* frame_host,
    mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {}

void BindBadgeServiceForServiceWorker(
    const content::ServiceWorkerVersionBaseInfo& info,
    mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {}

#if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_SPEECH_SERVICE)
void BindMediaFoundationRendererNotifierHandler(
    content::RenderFrameHost* frame_host,
    mojo::PendingReceiver<media::mojom::MediaFoundationRendererNotifier>
        receiver) {}
#endif

void BindNetworkHintsHandler(
    content::RenderFrameHost* frame_host,
    mojo::PendingReceiver<network_hints::mojom::NetworkHintsHandler> receiver) {
  predictors::NetworkHintsHandlerImpl::Create(frame_host, std::move(receiver));
}

#if defined(OHOS_NO_STATE_PREFETCH)
void BindPrerenderCanceler(
    content::RenderFrameHost* frame_host,
    mojo::PendingReceiver<prerender::mojom::PrerenderCanceler> receiver) {
  auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
  if (!web_contents)
    return;

  auto* no_state_prefetch_contents =
      prerender::ChromeNoStatePrefetchContentsDelegate::FromWebContents(
          web_contents);
  if (!no_state_prefetch_contents)
    return;
  no_state_prefetch_contents->AddPrerenderCancelerReceiver(std::move(receiver));
}

void BindNoStatePrefetchProcessor(
    content::RenderFrameHost* frame_host,
    mojo::PendingReceiver<blink::mojom::NoStatePrefetchProcessor> receiver) {
  prerender::NoStatePrefetchProcessorImpl::Create(
      frame_host, std::move(receiver),
      std::make_unique<
          prerender::ChromeNoStatePrefetchProcessorImplDelegate>());
}
#endif  // defined(OHOS_NO_STATE_PREFETCH)

base::FilePath GetRootCachePath() {
  // The CefContext::ValidateCachePath method enforces the requirement that all
  // cache_path values be either equal to or a child of root_cache_path.
  return base::FilePath(
      CefString(&CefContext::Get()->settings().root_cache_path));
}

const extensions::Extension* GetEnabledExtensionFromSiteURL(
    content::BrowserContext* context,
    const GURL& site_url) {
  if (!site_url.SchemeIs(extensions::kExtensionScheme)) {
    return nullptr;
  }

  auto registry = extensions::ExtensionRegistry::Get(context);
  if (!registry) {
    return nullptr;
  }

  return registry->enabled_extensions().GetByID(site_url.host());
}

#if defined(OHOS_MULTI_WINDOW)
class PopupWindowCallbackImpl : public CefCallback {
 public:
  explicit PopupWindowCallbackImpl(
      content::mojom::FrameHost::GetCreateNewWindowCallback callback)
      : callback_(std::move(callback)),
        task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}

  ~PopupWindowCallbackImpl() override {}

  void Continue() override {
    if (task_runner_ && !task_runner_->RunsTasksInCurrentSequence()) {
      task_runner_->PostTask(
          FROM_HERE, base::BindOnce(&PopupWindowCallbackImpl::Continue, this));
      return;
    }
    LOG(INFO) << "PopupWindowCallbackImpl Continue";
    if (!callback_.is_null()) {
      std::move(callback_).Run(content::mojom::CreateNewWindowStatus::kSuccess);
    }
  }

  void Cancel() override {
    if (task_runner_ && !task_runner_->RunsTasksInCurrentSequence()) {
      task_runner_->PostTask(
          FROM_HERE, base::BindOnce(&PopupWindowCallbackImpl::Cancel, this));
      return;
    }
    LOG(INFO) << "PopupWindowCallbackImpl Cancel";
    if (!callback_.is_null()) {
      std::move(callback_).Run(content::mojom::CreateNewWindowStatus::kBlocked);
    }
  }

 private:
  content::mojom::FrameHost::GetCreateNewWindowCallback callback_;
  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  IMPLEMENT_REFCOUNTING(PopupWindowCallbackImpl);
};
#endif  // defined(OHOS_MULTI_WINDOW)

}  // namespace

AlloyContentBrowserClient::AlloyContentBrowserClient() = default;

AlloyContentBrowserClient::~AlloyContentBrowserClient() = default;

std::unique_ptr<content::BrowserMainParts>
AlloyContentBrowserClient::CreateBrowserMainParts(
    bool /* is_integration_test */) {
  auto browser_main_parts = std::make_unique<AlloyBrowserMainParts>();
  browser_main_parts_ = browser_main_parts.get();
  return browser_main_parts;
}

void AlloyContentBrowserClient::RenderProcessWillLaunch(
    content::RenderProcessHost* host) {
  const int id = host->GetID();
  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());

  if (extensions::ExtensionsEnabled()) {
    host->AddFilter(new extensions::ExtensionMessageFilter(id, profile));
  }

  // If the renderer process crashes then the host may already have
  // CefBrowserInfoManager as an observer. Try to remove it first before adding
  // to avoid DCHECKs.
  host->RemoveObserver(CefBrowserInfoManager::GetInstance());
  host->AddObserver(CefBrowserInfoManager::GetInstance());

  // Forwards dynamic parameters to CefRenderThreadObserver.
  Profile* original_profile = profile->GetOriginalProfile();
  RendererUpdaterFactory::GetForProfile(original_profile)
      ->InitializeRenderer(host);
}

bool AlloyContentBrowserClient::ShouldUseProcessPerSite(
    content::BrowserContext* browser_context,
    const GURL& site_url) {
  if (extensions::ExtensionsEnabled()) {
    if (auto profile = Profile::FromBrowserContext(browser_context)) {
      return extensions::ChromeContentBrowserClientExtensionsPart::
          ShouldUseProcessPerSite(profile, site_url);
    }
  }

  return content::ContentBrowserClient::ShouldUseProcessPerSite(browser_context,
                                                                site_url);
}

bool AlloyContentBrowserClient::ShouldUseSpareRenderProcessHost(
    content::BrowserContext* browser_context,
    const GURL& site_url) {
  if (extensions::ExtensionsEnabled()) {
    if (auto profile = Profile::FromBrowserContext(browser_context)) {
      return extensions::ChromeContentBrowserClientExtensionsPart::
          ShouldUseSpareRenderProcessHost(profile, site_url);
    }
  }

  return content::ContentBrowserClient::ShouldUseSpareRenderProcessHost(
      browser_context, site_url);
}

bool AlloyContentBrowserClient::DoesSiteRequireDedicatedProcess(
    content::BrowserContext* browser_context,
    const GURL& effective_site_url) {
  if (extensions::ExtensionsEnabled()) {
    return extensions::ChromeContentBrowserClientExtensionsPart::
        DoesSiteRequireDedicatedProcess(browser_context, effective_site_url);
  }

  return content::ContentBrowserClient::DoesSiteRequireDedicatedProcess(
      browser_context, effective_site_url);
}

bool AlloyContentBrowserClient::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
    base::StringPiece scheme,
    bool is_embedded_origin_secure) {
  // This is needed to bypass the normal SameSite rules for any chrome:// page
  // embedding a secure origin, regardless of the registrable domains of any
  // intervening frames. For example, this is needed for browser UI to interact
  // with SameSite cookies on accounts.google.com, which are used for logging
  // into Cloud Print from chrome://print, for displaying a list of available
  // accounts on the NTP (chrome://new-tab-page), etc.
  if (is_embedded_origin_secure && scheme == content::kChromeUIScheme) {
    return true;
  }

  if (extensions::ExtensionsEnabled()) {
    return scheme == extensions::kExtensionScheme;
  }

  return false;
}

bool AlloyContentBrowserClient::
    ShouldIgnoreSameSiteCookieRestrictionsWhenTopLevel(
        base::StringPiece scheme,
        bool is_embedded_origin_secure) {
  return is_embedded_origin_secure && scheme == content::kChromeUIScheme;
}

void AlloyContentBrowserClient::OverrideURLLoaderFactoryParams(
    content::BrowserContext* browser_context,
    const url::Origin& origin,
    bool is_for_isolated_world,
    network::mojom::URLLoaderFactoryParams* factory_params) {
  if (extensions::ExtensionsEnabled()) {
    extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
        browser_context, origin, is_for_isolated_world, factory_params);
  }
}

void AlloyContentBrowserClient::GetAdditionalWebUISchemes(
    std::vector<std::string>* additional_schemes) {
  // Any schemes listed here are treated as WebUI schemes but do not get WebUI
  // bindings. Also, view-source is allowed for these schemes. WebUI schemes
  // will not be passed to HandleExternalProtocol.
#if defined(OHOS_ARKWEB_EXTENSIONS)
  additional_schemes->push_back(content::kArkWebUIScheme);
#endif
}

void AlloyContentBrowserClient::GetAdditionalViewSourceSchemes(
    std::vector<std::string>* additional_schemes) {
  GetAdditionalWebUISchemes(additional_schemes);

  additional_schemes->push_back(extensions::kExtensionScheme);
#if defined(OHOS_ARKWEB_EXTENSIONS)
  additional_schemes->push_back(content::kArkWebUIScheme);
#endif
}

std::unique_ptr<ui::SelectFilePolicy>
AlloyContentBrowserClient::CreateSelectFilePolicy(
    content::WebContents* web_contents) {
  return std::make_unique<ChromeSelectFilePolicy>(web_contents);
}

void AlloyContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
    std::vector<std::string>* additional_allowed_schemes) {
  ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
      additional_allowed_schemes);
  additional_allowed_schemes->push_back(content::kChromeDevToolsScheme);
  additional_allowed_schemes->push_back(content::kChromeUIScheme);
  additional_allowed_schemes->push_back(content::kChromeUIUntrustedScheme);
#if defined(OHOS_ARKWEB_EXTENSIONS)
  additional_allowed_schemes->push_back(content::kArkWebUIScheme);
#endif
}

bool AlloyContentBrowserClient::IsWebUIAllowedToMakeNetworkRequests(
    const url::Origin& origin) {
  return scheme::IsWebUIAllowedToMakeNetworkRequests(origin);
}

bool AlloyContentBrowserClient::IsHandledURL(const GURL& url) {
  if (!url.is_valid()) {
    return false;
  }
  const std::string& scheme = url.scheme();
  DCHECK_EQ(scheme, base::ToLowerASCII(scheme));

  if (scheme::IsInternalHandledScheme(scheme)) {
    return true;
  }

  return CefAppManager::Get()->HasCustomScheme(scheme);
}

void AlloyContentBrowserClient::SiteInstanceGotProcess(
    content::SiteInstance* site_instance) {
  if (!extensions::ExtensionsEnabled()) {
    return;
  }

  CHECK(site_instance->HasProcess());

  auto context = site_instance->GetBrowserContext();

  // Only add the process to the map if the SiteInstance's site URL is already
  // a chrome-extension:// URL. This includes hosted apps, except in rare cases
  // that a URL in the hosted app's extent is not treated as a hosted app (e.g.,
  // for isolated origins or cross-site iframes). For that case, don't look up
  // the hosted app's Extension from the site URL using GetExtensionOrAppByURL,
  // since it isn't treated as a hosted app.
  const auto extension =
      GetEnabledExtensionFromSiteURL(context, site_instance->GetSiteURL());
  if (!extension) {
    return;
  }

  extensions::ProcessMap::Get(context)->Insert(
      extension->id(), site_instance->GetProcess()->GetID(),
      site_instance->GetId());
}

void AlloyContentBrowserClient::SiteInstanceDeleting(
    content::SiteInstance* site_instance) {
  if (!extensions::ExtensionsEnabled()) {
    return;
  }

  if (!site_instance->HasProcess()) {
    return;
  }

  auto context = site_instance->GetBrowserContext();
  auto registry = extensions::ExtensionRegistry::Get(context);
  if (!registry) {
    return;
  }

  auto extension = registry->enabled_extensions().GetExtensionOrAppByURL(
      site_instance->GetSiteURL());
  if (!extension) {
    return;
  }

  extensions::ProcessMap::Get(context)->Remove(
      extension->id(), site_instance->GetProcess()->GetID(),
      site_instance->GetId());
}

void AlloyContentBrowserClient::BindHostReceiverForRenderer(
    content::RenderProcessHost* render_process_host,
    mojo::GenericPendingReceiver receiver) {
  if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckHost>()) {
    SpellCheckHostChromeImpl::Create(render_process_host->GetID(),
                                     std::move(host_receiver));
    return;
  }

#if BUILDFLAG(HAS_SPELLCHECK_PANEL)
  if (auto panel_host_receiver =
          receiver.As<spellcheck::mojom::SpellCheckPanelHost>()) {
    SpellCheckPanelHostImpl::Create(render_process_host->GetID(),
                                    std::move(panel_host_receiver));
    return;
  }
#endif  // BUILDFLAG(HAS_SPELLCHECK_PANEL)
}

void AlloyContentBrowserClient::AppendExtraCommandLineSwitches(
    base::CommandLine* command_line,
    int child_process_id) {
  const base::CommandLine* browser_cmd = base::CommandLine::ForCurrentProcess();

  {
    // Propagate the following switches to all command lines (along with any
    // associated values) if present in the browser command line.
    static const char* const kSwitchNames[] = {
      switches::kDisablePackLoading,
#if BUILDFLAG(IS_MAC)
      switches::kFrameworkDirPath,
      switches::kMainBundlePath,
#endif
      switches::kLocalesDirPath,
      switches::kLogSeverity,
      switches::kResourcesDirPath,
      embedder_support::kUserAgent,
      switches::kUserAgentProductAndVersion,
    };
    command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
                                   std::size(kSwitchNames));
  }

  const std::string& process_type =
      command_line->GetSwitchValueASCII(switches::kProcessType);

#if BUILDFLAG(IS_OHOS)
  if (process_type == switches::kZygoteProcess ||
      (browser_cmd->HasSwitch(switches::kNoZygote) &&
       process_type == switches::kRendererProcess)) {
    static const char* const kSwitchNames[] = {
        switches::kUserDataDir,
    };
    command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
                                   std::size(kSwitchNames));
  }
#endif

  if (process_type == switches::kRendererProcess) {
    // Propagate the following switches to the renderer command line (along with
    // any associated values) if present in the browser command line.
    static const char* const kSwitchNames[] = {
      switches::kDisableExtensions,
      switches::kDisablePdfExtension,
      switches::kDisablePrintPreview,
      switches::kDisableScrollBounce,
      switches::kDisableSpellChecking,
      switches::kEnableSpeechInput,
      switches::kUncaughtExceptionStackSize,
      network::switches::kUnsafelyTreatInsecureOriginAsSecure,
#if BUILDFLAG(IS_OHOS)
      switches::kUserDataDir,
#endif
#if defined(OHOS_ARKWEB_EXTENSIONS)
      extensions::switches::kAllowHTTPBackgroundPage,
      extensions::switches::kAllowLegacyExtensionManifests,
      extensions::switches::kDisableExtensionsHttpThrottling,
      extensions::switches::kEnableExperimentalExtensionApis,
      extensions::switches::kExtensionsOnChromeURLs,
      extensions::switches::kSetExtensionThrottleTestParams,  // For tests only.
      extensions::switches::kAllowlistedExtensionID,
#endif
    };
    command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
                                   std::size(kSwitchNames));

    if (extensions::ExtensionsEnabled()) {
      content::RenderProcessHost* process =
          content::RenderProcessHost::FromID(child_process_id);
      auto browser_context = process->GetBrowserContext();
      CefBrowserContext* cef_browser_context =
          process ? CefBrowserContext::FromBrowserContext(browser_context)
                  : nullptr;
      if (cef_browser_context) {
        if (cef_browser_context->IsPrintPreviewSupported()) {
          command_line->AppendSwitch(switches::kEnablePrintPreview);
        }

        // Based on ChromeContentBrowserClientExtensionsPart::
        // AppendExtraRendererCommandLineSwitches
        if (extensions::ProcessMap::Get(browser_context)
                ->Contains(process->GetID())) {
          command_line->AppendSwitch(extensions::switches::kExtensionProcess);
        }
      }
    }
  } else {
    // Propagate the following switches to non-renderer command line (along with
    // any associated values) if present in the browser command line.
    static const char* const kSwitchNames[] = {
        switches::kLang,
    };
    command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
                                   std::size(kSwitchNames));
  }

  // Necessary to populate DIR_USER_DATA in sub-processes.
  // See resource_util.cc GetUserDataPath.
  base::FilePath user_data_dir;
  if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
    command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
  }

#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
  if (process_type == switches::kZygoteProcess) {
    if (browser_cmd->HasSwitch(switches::kBrowserSubprocessPath)) {
      // Force use of the sub-process executable path for the zygote process.
      const base::FilePath& subprocess_path =
          browser_cmd->GetSwitchValuePath(switches::kBrowserSubprocessPath);
      if (!subprocess_path.empty()) {
        command_line->SetProgram(subprocess_path);
      }
    }

    // Propagate the following switches to the zygote command line (along with
    // any associated values) if present in the browser command line.
    static const char* const kSwitchNames[] = {
        switches::kLogFile,
    };
    command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
                                   std::size(kSwitchNames));
  }

  if (crash_reporting::Enabled()) {
    int fd;
    pid_t pid;
    if (crash_reporter::GetHandlerSocket(&fd, &pid)) {
      command_line->AppendSwitchASCII(
          crash_reporter::switches::kCrashpadHandlerPid,
          base::NumberToString(pid));
    }
  }
#endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)

  CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
  if (app.get()) {
    CefRefPtr<CefBrowserProcessHandler> handler =
        app->GetBrowserProcessHandler();
    if (handler.get()) {
      CefRefPtr<CefCommandLineImpl> commandLinePtr(
          new CefCommandLineImpl(command_line, false, false));
      handler->OnBeforeChildProcessLaunch(commandLinePtr.get());
      std::ignore = commandLinePtr->Detach(nullptr);
    }
  }
}

std::string AlloyContentBrowserClient::GetApplicationLocale() {
  return g_browser_process->GetApplicationLocale();
}

scoped_refptr<network::SharedURLLoaderFactory>
AlloyContentBrowserClient::GetSystemSharedURLLoaderFactory() {
  DCHECK(
      content::BrowserThread::CurrentlyOn(content::BrowserThread::UI) ||
      !content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI));

  if (!SystemNetworkContextManager::GetInstance()) {
    return nullptr;
  }

  return SystemNetworkContextManager::GetInstance()
      ->GetSharedURLLoaderFactory();
}

network::mojom::NetworkContext*
AlloyContentBrowserClient::GetSystemNetworkContext() {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK(SystemNetworkContextManager::GetInstance());
  return SystemNetworkContextManager::GetInstance()->GetContext();
}

content::MediaObserver* AlloyContentBrowserClient::GetMediaObserver() {
  return CefMediaCaptureDevicesDispatcher::GetInstance();
}

content::SpeechRecognitionManagerDelegate*
AlloyContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
  const base::CommandLine* command_line =
      base::CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kEnableSpeechInput)) {
    return new CefSpeechRecognitionManagerDelegate();
  }

  return nullptr;
}

content::GeneratedCodeCacheSettings
AlloyContentBrowserClient::GetGeneratedCodeCacheSettings(
    content::BrowserContext* context) {
  // If we pass 0 for size, disk_cache will pick a default size using the
  // heuristics based on available disk size. These are implemented in
  // disk_cache::PreferredCacheSize in net/disk_cache/cache_util.cc.
  const base::FilePath& cache_path = context->GetPath();
  return content::GeneratedCodeCacheSettings(!cache_path.empty() /* enabled */,
                                             0 /* size */, cache_path);
}

void AlloyContentBrowserClient::AllowCertificateError(
    content::WebContents* web_contents,
    int cert_error,
    const net::SSLInfo& ssl_info,
    const GURL& request_url,
    bool is_main_frame_request,
    bool strict_enforcement,
#ifdef OHOS_NETWORK_LOAD
    const GURL& origin_url,
    const std::string& referrer,
#endif
    base::OnceCallback<void(content::CertificateRequestResultType)> callback) {
#ifdef OHOS_NETWORK_LOAD
  auto returned_callback = certificate_query::AllowAllCertificateError(
      web_contents, cert_error, ssl_info, request_url, is_main_frame_request,
      strict_enforcement,
      origin_url,
      referrer,
      std::move(callback), /*default_disallow=*/true
      );
#else
  auto returned_callback = certificate_query::AllowCertificateError(
      web_contents, cert_error, ssl_info, request_url, is_main_frame_request,
      strict_enforcement,
      std::move(callback), /*default_disallow=*/true
      );
#endif
  // Callback should not be returned.
  DCHECK(returned_callback.is_null());
}

base::OnceClosure AlloyContentBrowserClient::SelectClientCertificate(
    content::WebContents* web_contents,
    net::SSLCertRequestInfo* cert_request_info,
    net::ClientCertIdentityList client_certs,
    std::unique_ptr<content::ClientCertificateDelegate> delegate) {
  CEF_REQUIRE_UIT();

#if BUILDFLAG(IS_OHOS)
  LOG(INFO) << "AlloyContentBrowserClient::SelectClientCertificate";
  std::string host = cert_request_info->host_and_port.host();
  int port = cert_request_info->host_and_port.port();

  if (AlloyClientCertLookupTable::IsDenied(host, port)) {
    LOG(INFO) << "AlloyContentBrowserClient::SelectClientCertificate is denied";
    delegate->ContinueWithCertificate(nullptr, nullptr);
    return base::OnceClosure();
  }
#endif

  CefRefPtr<CefRequestHandler> handler;
  CefRefPtr<AlloyBrowserHostImpl> browser =
      AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
  if (browser.get()) {
    CefRefPtr<CefClient> client = browser->GetClient();
    if (client.get()) {
      handler = client->GetRequestHandler();
    }
  }

  if (!handler.get()) {
#if BUILDFLAG(IS_OHOS)
    LOG(ERROR) << "AlloyContentBrowserClient::SelectClientCertificate get "
                  "handler failed.";
#endif
    delegate->ContinueWithCertificate(nullptr, nullptr);
    return base::OnceClosure();
  }

  CefRequestHandler::X509CertificateList certs;
  for (net::ClientCertIdentityList::iterator iter = client_certs.begin();
       iter != client_certs.end(); iter++) {
    certs.push_back(new CefX509CertificateImpl(std::move(*iter)));
  }

#if BUILDFLAG(IS_OHOS)
  std::vector<std::string> key_types;
  for (size_t i = 0; i < cert_request_info->cert_key_types.size(); ++i) {
    switch (cert_request_info->cert_key_types[i]) {
      case net::SSLClientCertType::kRsaSign:
        key_types.push_back("RSA");
        break;
      case net::SSLClientCertType::kEcdsaSign:
        key_types.push_back("ECDSA");
        break;
      default:
        break;
    }
  }
  std::vector<CefString> key_types_cef;
  TransferVector(key_types, key_types_cef);
  std::vector<CefString> cert_authorities_cef;
  TransferVector(cert_request_info->cert_authorities, cert_authorities_cef);
#endif

  CefRefPtr<CefSelectClientCertificateCallbackImpl> callbackImpl(
      new CefSelectClientCertificateCallbackImpl(std::move(delegate)
#if BUILDFLAG(IS_OHOS)
                                                     ,
                                                 host, port
#endif
                                                 ));

  bool proceed = handler->OnSelectClientCertificate(
      browser.get(), cert_request_info->is_proxy,
#if BUILDFLAG(IS_OHOS)
      host, port, key_types_cef, cert_authorities_cef,
#else
      cert_request_info->host_and_port.host(),
      cert_request_info->host_and_port.port(),
#endif
      certs, callbackImpl.get());
  LOG(INFO)
      << "AlloyContentBrowserClient::SelectClientCertificate end: prceed = "
      << proceed;

#if !BUILDFLAG(IS_OHOS)
  if (!proceed && !certs.empty()) {
    callbackImpl->Select(certs[0]);
  }
#endif

  return base::OnceClosure();
}

#if defined(OHOS_MULTI_WINDOW)
bool AlloyContentBrowserClient::CanCreateWindow(
    content::RenderFrameHost* opener,
    const GURL& target_url,
    WindowOpenDisposition disposition,
    bool user_gesture,
    content::mojom::FrameHost::GetCreateNewWindowCallback callback) {
  CEF_REQUIRE_UIT();
  content::WebContents* web_contents =
      content::WebContents::FromRenderFrameHost(opener);
  CefRefPtr<CefBrowserHostBase> browser_host =
      CefBrowserHostBase::GetBrowserForContents(web_contents);
  if (!browser_host) {
    std::move(callback).Run(content::mojom::CreateNewWindowStatus::kBlocked);
    return false;
  }
  if (!browser_host->settings().javascript_can_open_windows_automatically &&
      !user_gesture) {
    LOG(INFO) << "javascript_can_open_windows_automatically false";
    std::move(callback).Run(content::mojom::CreateNewWindowStatus::kBlocked);
    return false;
  }
  if (!browser_host->settings().supports_multiple_windows) {
    LOG(INFO) << "supports_multiple_windows is false";
    std::move(callback).Run(content::mojom::CreateNewWindowStatus::kBlocked);
    return false;
  }
  CefRefPtr<PopupWindowCallbackImpl> callbackImpl =
      new PopupWindowCallbackImpl(std::move(callback));
  return CefBrowserInfoManager::GetInstance()->CanCreateWindow(
      opener, target_url, disposition, user_gesture, callbackImpl);
}
#endif  // defined(OHOS_MULTI_WINDOW)

bool AlloyContentBrowserClient::CanCreateWindow(
    content::RenderFrameHost* opener,
    const GURL& opener_url,
    const GURL& opener_top_level_frame_url,
    const url::Origin& source_origin,
    content::mojom::WindowContainerType container_type,
    const GURL& target_url,
    const content::Referrer& referrer,
    const std::string& frame_name,
    WindowOpenDisposition disposition,
    const blink::mojom::WindowFeatures& features,
    bool user_gesture,
    bool opener_suppressed,
    bool* no_javascript_access) {
  CEF_REQUIRE_UIT();
  *no_javascript_access = false;

#if defined(OHOS_MULTI_WINDOW)
  content::WebContents* web_contents =
      content::WebContents::FromRenderFrameHost(opener);
  CefRefPtr<CefBrowserHostBase> browser_host =
      CefBrowserHostBase::GetBrowserForContents(web_contents);
  if (!browser_host->settings().supports_multiple_windows) {
    if (browser_host->settings().javascript_can_open_windows_automatically ||
        user_gesture) {
      LOG(INFO) << "allow load url";
      return true;
    }
    LOG(INFO) << "supports_multiple_windows is false";
    return false;
  }
  if (!browser_host->settings().javascript_can_open_windows_automatically &&
      !user_gesture) {
    LOG(INFO) << "javascript_can_open_windows_automatically false";
    return false;
  }
#endif  // defined(OHOS_MULTI_WINDOW)

  return CefBrowserInfoManager::GetInstance()->CanCreateWindow(
      opener, target_url, referrer, frame_name, disposition, features,
      user_gesture, opener_suppressed, no_javascript_access);
}

void AlloyContentBrowserClient::OverrideWebkitPrefs(
    content::WebContents* web_contents,
    blink::web_pref::WebPreferences* prefs) {
  auto rvh = web_contents->GetRenderViewHost();

  // Using RVH instead of RFH here because rvh->GetMainFrame() may be nullptr
  // when this method is called.
  SkColor base_background_color;
  renderer_prefs::PopulateWebPreferences(rvh, *prefs, base_background_color);

#if BUILDFLAG(IS_OHOS) && defined(OHOS_EX_FORCE_ZOOM)
  prefs->force_enable_zoom = web_contents->GetForceEnableZoom();
#endif

#if BUILDFLAG(IS_OHOS) && defined(OHOS_EX_BLANK_TARGET_POPUP_INTERCEPT)
  prefs->blank_target_popup_intercept_enabled =
      web_contents->GetEnableBlankTargetPopupIntercept();
#endif

  web_contents->SetPageBaseBackgroundColor(base_background_color);
}

bool AlloyContentBrowserClient::OverrideWebPreferencesAfterNavigation(
    content::WebContents* web_contents,
    blink::web_pref::WebPreferences* prefs) {
  return renderer_prefs::PopulateWebPreferencesAfterNavigation(web_contents,
                                                               *prefs);
}

void AlloyContentBrowserClient::BrowserURLHandlerCreated(
    content::BrowserURLHandler* handler) {
  scheme::BrowserURLHandlerCreated(handler);
}

std::string AlloyContentBrowserClient::GetDefaultDownloadName() {
  return "download";
}

void AlloyContentBrowserClient::DidCreatePpapiPlugin(
    content::BrowserPpapiHost* browser_host) {
  browser_host->GetPpapiHost()->AddHostFactoryFilter(
      std::unique_ptr<ppapi::host::HostFactory>(
          new ChromeBrowserPepperHostFactory(browser_host)));
}

std::unique_ptr<content::DevToolsManagerDelegate>
AlloyContentBrowserClient::CreateDevToolsManagerDelegate() {
  return std::make_unique<CefDevToolsManagerDelegate>();
}

void AlloyContentBrowserClient::
    RegisterAssociatedInterfaceBindersForRenderFrameHost(
        content::RenderFrameHost& render_frame_host,
        blink::AssociatedInterfaceRegistry& associated_registry) {
#ifdef OHOS_FCP
  associated_registry.AddInterface<page_load_metrics::mojom::PageLoadMetrics>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
             mojo::PendingAssociatedReceiver<
                 page_load_metrics::mojom::PageLoadMetrics> receiver) {
            page_load_metrics::MetricsWebContentsObserver::BindPageLoadMetrics(
                std::move(receiver), render_frame_host);
          },
          &render_frame_host));
#endif

#ifdef OHOS_ARKWEB_ADBLOCK
  associated_registry.AddInterface<
      subresource_filter::mojom::SubresourceFilterHost>(base::BindRepeating(
      [](content::RenderFrameHost* render_frame_host,
         mojo::PendingAssociatedReceiver<
             subresource_filter::mojom::SubresourceFilterHost> receiver) {
        subresource_filter::ContentSubresourceFilterThrottleManager::
            BindReceiver(std::move(receiver), render_frame_host);
      },
      &render_frame_host));

  associated_registry.AddInterface<
      subresource_filter::mojom::UserSubresourceFilterHost>(base::BindRepeating(
      [](content::RenderFrameHost* render_frame_host,
         mojo::PendingAssociatedReceiver<
             subresource_filter::mojom::UserSubresourceFilterHost> receiver) {
        subresource_filter::ContentSubresourceFilterThrottleManager::
            BindUserReceiver(std::move(receiver), render_frame_host);
      },
      &render_frame_host));
#endif

  associated_registry.AddInterface<extensions::mojom::LocalFrameHost>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
             mojo::PendingAssociatedReceiver<extensions::mojom::LocalFrameHost>
                 receiver) {
            extensions::ExtensionWebContentsObserver::BindLocalFrameHost(
                std::move(receiver), render_frame_host);
          },
          &render_frame_host));

#if BUILDFLAG(IS_OHOS)
  associated_registry.AddInterface<autofill::mojom::AutofillDriver>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
             mojo::PendingAssociatedReceiver<autofill::mojom::AutofillDriver>
                 receiver) {
            autofill::ContentAutofillDriverFactory::BindAutofillDriver(
                std::move(receiver), render_frame_host);
          },
          &render_frame_host));

#if defined(OHOS_EX_PASSWORD) || defined(OHOS_PASSWORD_AUTOFILL)
  associated_registry.AddInterface<autofill::mojom::PasswordManagerDriver>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
              mojo::PendingAssociatedReceiver<
                  autofill::mojom::PasswordManagerDriver> receiver) {
            password_manager::ContentPasswordManagerDriverFactory::
                BindPasswordManagerDriver(std::move(receiver),
                                          render_frame_host);
          },
          &render_frame_host));

  LOG(INFO) << "PASSWORD bind associated receiver from frame";
#endif  // defined(OHOS_EX_PASSWORD) || defined(OHOS_PASSWORD_AUTOFILL)
#endif  // BUILDFLAG(IS_OHOS)
  associated_registry.AddInterface<pdf::mojom::PdfService>(base::BindRepeating(
      [](content::RenderFrameHost* render_frame_host,
         mojo::PendingAssociatedReceiver<pdf::mojom::PdfService> receiver) {
        pdf::PDFWebContentsHelper::BindPdfService(std::move(receiver),
                                                  render_frame_host);
      },
      &render_frame_host));

#if defined(OHOS_PRINT)
  associated_registry.AddInterface<printing::mojom::PrintManagerHost>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
             mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost>
                 receiver) {
            printing::OhosPrintManager::BindPrintManagerHost(std::move(receiver),
                                                            render_frame_host);
          },
          &render_frame_host));
#else
  associated_registry.AddInterface<printing::mojom::PrintManagerHost>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
             mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost>
                 receiver) {
            printing::PrintViewManager::BindPrintManagerHost(
                std::move(receiver), render_frame_host);
          },
          &render_frame_host));
#endif // defined(OHOS_PRINT)

  associated_registry.AddInterface<security_interstitials::mojom::InterstitialCommands>(
      base::BindRepeating(
        [](content::RenderFrameHost* render_frame_host,
          mojo::PendingAssociatedReceiver<
              security_interstitials::mojom::InterstitialCommands> receiver) {
          security_interstitials::SecurityInterstitialTabHelper::
            BindInterstitialCommands(std::move(receiver), render_frame_host);
      },
      &render_frame_host));
}

std::vector<std::unique_ptr<content::NavigationThrottle>>
AlloyContentBrowserClient::CreateThrottlesForNavigation(
    content::NavigationHandle* navigation_handle) {
  throttle::NavigationThrottleList throttles;

  if (extensions::ExtensionsEnabled()) {
    auto pdf_iframe_throttle =
        PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(navigation_handle);
    if (pdf_iframe_throttle) {
      throttles.push_back(std::move(pdf_iframe_throttle));
    }

    auto pdf_throttle = pdf::PdfNavigationThrottle::MaybeCreateThrottleFor(
        navigation_handle, std::make_unique<ChromePdfStreamDelegate>());
    if (pdf_throttle) {
      throttles.push_back(std::move(pdf_throttle));
    }
  }

#ifdef OHOS_FCP
  if (navigation_handle->IsInMainFrame()) {
    // MetricsNavigationThrottle requires that it runs before
    // NavigationThrottles that may delay or cancel navigations, so only
    // NavigationThrottles that don't delay or cancel navigations (e.g.
    // throttles that are only observing callbacks without affecting navigation
    // behavior) should be added before MetricsNavigationThrottle.
    throttles.push_back(page_load_metrics::MetricsNavigationThrottle::Create(
        navigation_handle));
  }
#endif

#if OHOS_URL_TRUST_LIST
  throttles.push_back(ohos_safe_browsing::OhosUrlTrustListNavigationThrottle::Create(
    navigation_handle));
#endif

#if defined(OHOS_ARKWEB_EXTENSIONS)
  throttles.push_back(std::make_unique<extensions::ExtensionNavigationThrottle>(
      navigation_handle));

  MaybeAddThrottle(extensions::ExtensionsBrowserClient::Get()
                       ->GetUserScriptListener()
                       ->CreateNavigationThrottle(navigation_handle),
                   &throttles);
#endif

  throttle::CreateThrottlesForNavigation(navigation_handle, throttles);

#ifdef OHOS_ARKWEB_ADBLOCK
  CreateSubresourceFilterWebContentsHelper(navigation_handle);
  if (auto* throttle_manager =
          subresource_filter::ContentSubresourceFilterThrottleManager::
              FromNavigationHandle(*navigation_handle)) {
    throttle_manager->MaybeAppendNavigationThrottles(navigation_handle,
                                                     &throttles);
  }
#endif  // OHOS_ARKWEB_ADBLOCK

  return throttles;
}

std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
AlloyContentBrowserClient::CreateURLLoaderThrottles(
    const network::ResourceRequest& request,
    content::BrowserContext* browser_context,
    const base::RepeatingCallback<content::WebContents*()>& wc_getter,
    content::NavigationUIData* navigation_ui_data,
    int frame_tree_node_id) {
  std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result;

  // Used to substitute View ID for PDF contents when using the PDF plugin.
  result.push_back(std::make_unique<PluginResponseInterceptorURLLoaderThrottle>(
      request.destination, frame_tree_node_id));

  Profile* profile = Profile::FromBrowserContext(browser_context);

  chrome::mojom::DynamicParamsPtr dynamic_params =
      chrome::mojom::DynamicParams::New(
#if BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS)
          /*bound_session_params=*/nullptr,
#endif
          profile->GetPrefs()->GetBoolean(
              policy::policy_prefs::kForceGoogleSafeSearch),
          profile->GetPrefs()->GetInteger(
              policy::policy_prefs::kForceYouTubeRestrict),
          profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps));
  result.push_back(std::make_unique<GoogleURLLoaderThrottle>(
#if BUILDFLAG(ENABLE_BOUND_SESSION_CREDENTIALS)
      /*bound_session_request_throttled_listener=*/nullptr,
#endif
      std::move(dynamic_params)));

#if defined(OHOS_NO_STATE_PREFETCH)
  prerender::NoStatePrefetchManager* no_state_prefetch_manager =
      prerender::NoStatePrefetchManagerFactory::GetForBrowserContext(
          browser_context);
  if (no_state_prefetch_manager) {
    prerender::NoStatePrefetchContents* no_state_prefetch_contents =
        no_state_prefetch_manager->GetNoStatePrefetchContents(wc_getter.Run());
    if (no_state_prefetch_contents) {
      mojo::PendingRemote<prerender::mojom::PrerenderCanceler> canceler;
      no_state_prefetch_contents->AddPrerenderCancelerReceiver(
          canceler.InitWithNewPipeAndPassReceiver());
      result.push_back(std::make_unique<prerender::PrerenderURLLoaderThrottle>(
          prerender::PrerenderHistograms::GetHistogramPrefix(
              no_state_prefetch_contents->origin()),
          std::move(canceler)));
    }
  }
#endif  // defined(OHOS_NO_STATE_PREFETCH)

#if BUILDFLAG(IS_OHOS)
  if (request.destination == network::mojom::RequestDestination::kDocument &&
      request.url.SchemeIs(url::kHttpsScheme) &&
      request.transition_type != static_cast<int32_t>(ui::PAGE_TRANSITION_RELOAD) &&
      (request.transition_type & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) == 0 &&
      (request.transition_type & ui::PAGE_TRANSITION_FORWARD_BACK) == 0) {
    bool is_same_host = true;
    if (request.request_initiator.has_value()) {
      if (request.request_initiator.value().host() != request.url.host()) {
        is_same_host = false;
      }
    } else {
      is_same_host = false;
    }

    if (!is_same_host) {
      result.push_back(std::make_unique<throttle::OhosAppLinkThrottle>(frame_tree_node_id));
    }
  }
#endif
  return result;
}

std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
AlloyContentBrowserClient::WillCreateURLLoaderRequestInterceptors(
    content::NavigationUIData* navigation_ui_data,
    int frame_tree_node_id) {
  std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
      interceptors;

  if (extensions::ExtensionsEnabled()) {
    auto pdf_interceptor =
        pdf::PdfURLLoaderRequestInterceptor::MaybeCreateInterceptor(
            frame_tree_node_id, std::make_unique<ChromePdfStreamDelegate>());
    if (pdf_interceptor) {
      interceptors.push_back(std::move(pdf_interceptor));
    }
  }

  return interceptors;
}

#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
void AlloyContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
    const base::CommandLine& command_line,
    int child_process_id,
    content::PosixFileDescriptorInfo* mappings) {
  int crash_signal_fd = GetCrashSignalFD();
  if (crash_signal_fd >= 0) {
    mappings->Share(kCrashDumpSignal, crash_signal_fd);
  }
}
#endif  //  BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)

void AlloyContentBrowserClient::ExposeInterfacesToRenderer(
    service_manager::BinderRegistry* registry,
    blink::AssociatedInterfaceRegistry* associated_registry,
    content::RenderProcessHost* host) {
  associated_registry->AddInterface<chrome::mojom::PluginInfoHost>(
      base::BindRepeating(&BindPluginInfoHost, host->GetID()));

  if (extensions::ExtensionsEnabled()) {
    associated_registry->AddInterface<extensions::mojom::EventRouter>(
        base::BindRepeating(&extensions::EventRouter::BindForRenderer,
                            host->GetID()));
    associated_registry->AddInterface<guest_view::mojom::GuestViewHost>(
        base::BindRepeating(
            &extensions::ExtensionsGuestView::CreateForComponents,
            host->GetID()));
    associated_registry->AddInterface<extensions::mojom::GuestView>(
        base::BindRepeating(
            &extensions::ExtensionsGuestView::CreateForExtensions,
            host->GetID()));
    associated_registry->AddInterface<extensions::mojom::RendererHost>(
        base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
                            host->GetID()));
#if defined(OHOS_ARKWEB_EXTENSIONS)
    associated_registry->AddInterface<extensions::mojom::ServiceWorkerHost>(
        base::BindRepeating(&extensions::ServiceWorkerHost::BindReceiver,
                            host->GetID()));
#endif
  }

  CefBrowserManager::ExposeInterfacesToRenderer(registry, associated_registry,
                                                host);

#if BUILDFLAG(IS_OHOS)
  CefReportManager::ExposeInterfacesToRenderer(registry, associated_registry, host);
#endif
}

#if !BUILDFLAG(IS_OHOS)
std::unique_ptr<net::ClientCertStore>
AlloyContentBrowserClient::CreateClientCertStore(
    content::BrowserContext* browser_context) {
  // Match the logic in ProfileNetworkContextService::CreateClientCertStore.
#if BUILDFLAG(USE_NSS_CERTS)
  // TODO: Add support for client implementation of crypto password dialog.
  return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
      net::ClientCertStoreNSS::PasswordDelegateFactory()));
#elif BUILDFLAG(IS_WIN)
  return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
#elif BUILDFLAG(IS_MAC)
  return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
#else
#error Unknown platform.
#endif
}
#endif

std::unique_ptr<content::LoginDelegate>
AlloyContentBrowserClient::CreateLoginDelegate(
    const net::AuthChallengeInfo& auth_info,
    content::WebContents* web_contents,
    const content::GlobalRequestID& request_id,
    bool is_request_for_main_frame,
    const GURL& url,
    scoped_refptr<net::HttpResponseHeaders> response_headers,
    bool first_auth_attempt,
    LoginAuthRequiredCallback auth_required_callback) {
#if defined(OHOS_ARKWEB_EXTENSIONS)
  return std::make_unique<net_service::LoginDelegate>(
      auth_info, web_contents, request_id, is_request_for_main_frame, url,
      response_headers, std::move(auth_required_callback));
#else
  return std::make_unique<net_service::LoginDelegate>(
      auth_info, web_contents, request_id, url,
      std::move(auth_required_callback));

#endif
}

void AlloyContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
    int frame_tree_node_id,
    ukm::SourceIdObj ukm_source_id,
    NonNetworkURLLoaderFactoryMap* factories) {
  if (!extensions::ExtensionsEnabled()) {
    return;
  }

  content::WebContents* web_contents =
      content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
  factories->emplace(
      extensions::kExtensionScheme,
      extensions::CreateExtensionNavigationURLLoaderFactory(
          web_contents->GetBrowserContext(), ukm_source_id,
          !!extensions::WebViewGuest::FromWebContents(web_contents)));
}

void AlloyContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
    int render_process_id,
    int render_frame_id,
    const absl::optional<url::Origin>& request_initiator_origin,
    NonNetworkURLLoaderFactoryMap* factories) {
#if BUILDFLAG(IS_OHOS)
  content::RenderFrameHost* frame_host =
      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
  content::WebContents* web_contents =
      content::WebContents::FromRenderFrameHost(frame_host);
  if (!web_contents) {
    return;
  }

  auto browser_context = web_contents->GetBrowserContext();
  if (!browser_context) {
    return;
  }

  factories->emplace(url::kFileScheme,
                     content::CreateFileURLLoaderFactory(
                         browser_context->GetPath(),
                         browser_context->GetSharedCorsOriginAccessList()));
#ifdef OHOS_HAP_DECOMPRESSED
  factories->emplace(url::kResourcesScheme,
                     content::CreateFileURLLoaderFactory(
                         browser_context->GetPath(),
                         browser_context->GetSharedCorsOriginAccessList()));
#endif
#endif

  if (!extensions::ExtensionsEnabled()) {
    return;
  }

  auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
                                                             render_frame_id);
  if (factory) {
    factories->emplace(extensions::kExtensionScheme, std::move(factory));
  }

#if !BUILDFLAG(IS_OHOS)
  content::RenderFrameHost* frame_host =
      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
  content::WebContents* web_contents =
      content::WebContents::FromRenderFrameHost(frame_host);
  if (!web_contents) {
    return;
  }
#endif

  extensions::CefExtensionWebContentsObserver* web_observer =
      extensions::CefExtensionWebContentsObserver::FromWebContents(
          web_contents);

  // There is nothing to do if no CefExtensionWebContentsObserver is attached
  // to the |web_contents|.
  if (!web_observer) {
    return;
  }

  const extensions::Extension* extension =
      web_observer->GetExtensionFromFrame(frame_host, false);
  if (!extension) {
    return;
  }

#if defined(OHOS_ARKWEB_EXTENSIONS)
  // For service worker contexts, we only allow file access. The remainder of
  // this code is used to allow extensions to access chrome:-scheme
  // resources, which we are moving away from.
  // TODO(crbug.com/1280411) Factories should not be created for unloaded
  // extensions.
  if (extension) {
    InitializeFileURLLoaderFactoryForExtension(
        render_process_id, browser_context, extension, factories);
  }
#endif

  std::vector<std::string> allowed_webui_hosts;
  // Support for chrome:// scheme if appropriate.
  if ((extension->is_extension() || extension->is_platform_app()) &&
      extensions::Manifest::IsComponentLocation(extension->location())) {
    // Components of chrome that are implemented as extensions or platform apps
    // are allowed to use chrome://resources/ and chrome://theme/ URLs.
    // See also HasCrossOriginWhitelistEntry.
    allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost);
    allowed_webui_hosts.emplace_back(chrome::kChromeUIThemeHost);
  }
  if (!allowed_webui_hosts.empty()) {
#if defined(OHOS_ARKWEB_EXTENSIONS)
    factories->emplace(
        content::kArkWebUIScheme,
        content::CreateWebUIURLLoaderFactory(
            frame_host, content::kArkWebUIScheme, allowed_webui_hosts));
#endif
    factories->emplace(content::kChromeUIScheme,
                       content::CreateWebUIURLLoaderFactory(
                           frame_host, content::kChromeUIScheme,
                           std::move(allowed_webui_hosts)));
  }
}

#if defined(OHOS_ARKWEB_EXTENSIONS)
void AlloyContentBrowserClient::
    RegisterNonNetworkWorkerMainResourceURLLoaderFactories(
        content::BrowserContext* browser_context,
        NonNetworkURLLoaderFactoryMap* factories) {
  DCHECK(browser_context);
  DCHECK(factories);

#if BUILDFLAG(ENABLE_EXTENSIONS)
  DCHECK(!extensions::ChromeContentBrowserClientExtensionsPart::
             AreExtensionsDisabledForProfile(browser_context));

  factories->emplace(
      extensions::kExtensionScheme,
      extensions::CreateExtensionWorkerMainResourceURLLoaderFactory(
          browser_context));
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
}

void AlloyContentBrowserClient::
    RegisterNonNetworkServiceWorkerUpdateURLLoaderFactories(
        content::BrowserContext* browser_context,
        NonNetworkURLLoaderFactoryMap* factories) {
  DCHECK(browser_context);
  DCHECK(factories);

#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (extensions::ChromeContentBrowserClientExtensionsPart::
          AreExtensionsDisabledForProfile(browser_context)) {
    return;
  }

  factories->emplace(
      extensions::kExtensionScheme,
      extensions::CreateExtensionServiceWorkerScriptURLLoaderFactory(
          browser_context));
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
}
#endif  // defined(OHOS_ARKWEB_EXTENSIONS)

bool AlloyContentBrowserClient::WillCreateURLLoaderFactory(
    content::BrowserContext* browser_context,
    content::RenderFrameHost* frame,
    int render_process_id,
    URLLoaderFactoryType type,
    const url::Origin& request_initiator,
    absl::optional<int64_t> navigation_id,
    ukm::SourceIdObj ukm_source_id,
    mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
    mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
        header_client,
    bool* bypass_redirect_checks,
    bool* disable_secure_dns,
    network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
  auto request_handler = net_service::CreateInterceptedRequestHandler(
      browser_context, frame, render_process_id,
      type == URLLoaderFactoryType::kNavigation,
      type == URLLoaderFactoryType::kDownload, request_initiator);

#if defined(OHOS_ARKWEB_EXTENSIONS)
  auto* web_request_api =
      extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
          browser_context);

  // NOTE: Some unit test environments do not initialize
  // BrowserContextKeyedAPI factories for e.g. WebRequest.
  if (web_request_api) {
    bool use_proxy_for_web_request =
        web_request_api->MaybeProxyURLLoaderFactory(
            browser_context, frame, render_process_id, type,
            std::move(navigation_id), ukm_source_id, factory_receiver,
            header_client, request_initiator);
    if (bypass_redirect_checks) {
      *bypass_redirect_checks = use_proxy_for_web_request;
    }
  }
#endif

#ifdef OHOS_NETWORK_LOAD
  net_service::ProxyURLLoaderFactory::CreateProxy(
      browser_context, factory_receiver, header_client,
      std::move(request_handler), factory_override);
#else
  net_service::ProxyURLLoaderFactory::CreateProxy(
      browser_context, factory_receiver, header_client,
      std::move(request_handler));
#endif

  return true;
}

#if defined(OHOS_ARKWEB_EXTENSIONS)
bool AlloyContentBrowserClient::WillInterceptWebSocket(
    content::RenderFrameHost* frame) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (!frame) {
    return false;
  }
  const auto* web_request_api =
      extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
          frame->GetBrowserContext());

  // NOTE: Some unit test environments do not initialize
  // BrowserContextKeyedAPI factories for e.g. WebRequest.
  if (!web_request_api) {
    return false;
  }
  return (web_request_api->MayHaveProxies() ||
          web_request_api->MayHaveWebsocketProxiesForExtensionTelemetry());
#else
  return false;
#endif
}

void AlloyContentBrowserClient::CreateWebSocket(
    content::RenderFrameHost* frame,
    WebSocketFactory factory,
    const GURL& url,
    const net::SiteForCookies& site_for_cookies,
    const absl::optional<std::string>& user_agent,
    mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
        handshake_client) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // TODO(crbug.com/1243518): Request w/o a frame also should be proxied.
  if (!frame) {
    return;
  }
  auto* web_request_api =
      extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
          frame->GetBrowserContext());

  DCHECK(web_request_api);
  web_request_api->ProxyWebSocket(frame, std::move(factory), url,
                                  site_for_cookies, user_agent,
                                  std::move(handshake_client));
#endif
}

void AlloyContentBrowserClient::WillCreateWebTransport(
    int process_id,
    int frame_routing_id,
    const GURL& url,
    const url::Origin& initiator_origin,
    mojo::PendingRemote<network::mojom::WebTransportHandshakeClient>
        handshake_client,
    WillCreateWebTransportCallback callback) {
  MaybeInterceptWebTransport(process_id, frame_routing_id, url,
                             initiator_origin, std::move(handshake_client),
                             std::move(callback));
}

void AlloyContentBrowserClient::MaybeInterceptWebTransport(
    int process_id,
    int frame_routing_id,
    const GURL& url,
    const url::Origin& initiator_origin,
    mojo::PendingRemote<network::mojom::WebTransportHandshakeClient>
        handshake_client,
    WillCreateWebTransportCallback callback) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  // TODO(1243518): Add a unit test which calls
  // ChromeContentBrowserClient::WillCreateWebTransport() with invalid process
  // id and routing id.
  auto* render_process_host = content::RenderProcessHost::FromID(process_id);
  if (!render_process_host) {
    std::move(callback).Run(std::move(handshake_client), absl::nullopt);
    return;
  }
  content::BrowserContext* browser_context =
      render_process_host->GetBrowserContext();
  auto* web_request_api =
      extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
          browser_context);
  // NOTE: Some unit test environments do not initialize BrowserContextKeyedAPI
  // factories like WebRequestAPI.
  if (!web_request_api) {
    std::move(callback).Run(std::move(handshake_client), absl::nullopt);
    return;
  }
  web_request_api->ProxyWebTransport(
      *render_process_host, frame_routing_id, url, initiator_origin,
      std::move(handshake_client), std::move(callback));
#else
  std::move(callback).Run(std::move(handshake_client), absl::nullopt);
#endif
}

bool AlloyContentBrowserClient::ShouldPreconnectNavigation(
    content::BrowserContext* browser_context) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // An extension could be blocking connections for privacy reasons, so skip
  // optimization if there are any extensions with WebRequest permissions.
  const auto* web_request_api =
      extensions::BrowserContextKeyedAPIFactory<extensions::WebRequestAPI>::Get(
          browser_context);
  if (!web_request_api || web_request_api->MayHaveProxies()) {
    return false;
  }
#endif
  return true;
}

content::AllowServiceWorkerResult AlloyContentBrowserClient::AllowServiceWorker(
    const GURL& scope,
    const net::SiteForCookies& site_for_cookies,
    const absl::optional<url::Origin>& top_frame_origin,
    const GURL& script_url,
    content::BrowserContext* context) {
  DCHECK(context);
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  GURL first_party_url = top_frame_origin ? top_frame_origin->GetURL() : GURL();

#if BUILDFLAG(ENABLE_EXTENSIONS)
  // Check if this is an extension-related service worker, and, if so, if it's
  // allowed (this can return false if, e.g., the extension is disabled).
  // If it's not allowed, return immediately. We deliberately do *not* report
  // to the PageSpecificContentSettings, since the service worker is blocked
  // because of the extension, rather than because of the user's content
  // settings.
  if (extensions::ExtensionsEnabled()) {
    if (!extensions::ChromeContentBrowserClientExtensionsPart::
            AllowServiceWorker(scope, first_party_url, script_url, context)) {
      return content::AllowServiceWorkerResult::No();
    }
  }
#endif

  Profile* profile = Profile::FromBrowserContext(context);
  return embedder_support::AllowServiceWorker(
      scope, site_for_cookies, top_frame_origin,
      CookieSettingsFactory::GetForProfile(profile).get(),
      HostContentSettingsMapFactory::GetForProfile(profile));
}

bool AlloyContentBrowserClient::MayDeleteServiceWorkerRegistration(
    const GURL& scope,
    content::BrowserContext* browser_context) {
  DCHECK(browser_context);
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (!extensions::ChromeContentBrowserClientExtensionsPart::
          MayDeleteServiceWorkerRegistration(scope, browser_context)) {
    return false;
  }
#endif

  return true;
}

content::StoragePartitionConfig
AlloyContentBrowserClient::GetStoragePartitionConfigForSite(
    content::BrowserContext* browser_context,
    const GURL& site) {
  // Default to the browser-wide storage partition and override based on |site|
  // below.
  content::StoragePartitionConfig default_storage_partition_config =
      content::StoragePartitionConfig::CreateDefault(browser_context);

  // A non-default storage partition is used in the following situations:
  // - To enforce process isolation between a more-trusted content (Chrome Apps,
  // Extensions, and Isolated Web Apps) and regular web content.
  // - For the <webview> tag, which Chrome Apps, Isolated Web Apps and WebUI use
  // to create temporary storage buckets for loading various kinds of web
  // content.
  //
  // In general, those use cases aren't considered part of the user's normal
  // browsing activity.
#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (site.SchemeIs(extensions::kExtensionScheme)) {
    // The host in an extension site URL is the extension_id.
    CHECK(site.has_host());
    return extensions::util::GetStoragePartitionConfigForExtensionId(
        site.host(), browser_context);
  }

  if (content::SiteIsolationPolicy::ShouldUrlUseApplicationIsolationLevel(
          browser_context, site)) {
    CHECK(site.SchemeIs(chrome::kIsolatedAppScheme));
    const base::expected<web_app::IsolatedWebAppUrlInfo, std::string>
        iwa_url_info = web_app::IsolatedWebAppUrlInfo::Create(site);
    if (!iwa_url_info.has_value()) {
      LOG(ERROR) << "Invalid isolated-app URL: " << site;
      return default_storage_partition_config;
    }
    return iwa_url_info->storage_partition_config(browser_context);
  }
#endif

  return default_storage_partition_config;
}

GURL AlloyContentBrowserClient::GetEffectiveURL(
    content::BrowserContext* browser_context,
    const GURL& url) {
  Profile* profile = Profile::FromBrowserContext(browser_context);
  if (!profile) {
    return url;
  }

#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (extensions::ChromeContentBrowserClientExtensionsPart::
          AreExtensionsDisabledForProfile(profile)) {
    return url;
  }

  return extensions::ChromeContentBrowserClientExtensionsPart::GetEffectiveURL(
      profile, url);
#else
  return url;
#endif
}

bool AlloyContentBrowserClient::
    ShouldCompareEffectiveURLsForSiteInstanceSelection(
        content::BrowserContext* browser_context,
        content::SiteInstance* candidate_site_instance,
        bool is_outermost_main_frame,
        const GURL& candidate_url,
        const GURL& destination_url) {
  DCHECK(browser_context);
  DCHECK(candidate_site_instance);
#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (extensions::ChromeContentBrowserClientExtensionsPart::
          AreExtensionsDisabledForProfile(browser_context)) {
    return true;
  }

  return extensions::ChromeContentBrowserClientExtensionsPart::
      ShouldCompareEffectiveURLsForSiteInstanceSelection(
          browser_context, candidate_site_instance, is_outermost_main_frame,
          candidate_url, destination_url);
#else
  return true;
#endif
}

// TODO(crbug.com/1087559): This is based on SubframeTask::GetTitle()
// implementation. Find a general solution to avoid code duplication.
std::string AlloyContentBrowserClient::GetSiteDisplayNameForCdmProcess(
    content::BrowserContext* browser_context,
    const GURL& site_url) {
  // By default, use the |site_url| spec as the display name.
  std::string name = site_url.spec();

#if BUILDFLAG(ENABLE_EXTENSIONS)
  // If |site_url| wraps a chrome extension ID, we can display the extension
  // name instead, which is more human-readable.
  if (site_url.SchemeIs(extensions::kExtensionScheme)) {
    const extensions::Extension* extension =
        extensions::ExtensionRegistry::Get(browser_context)
            ->enabled_extensions()
            .GetExtensionOrAppByURL(site_url);
    if (extension) {
      name = extension->name();
    }
  }
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)

  return name;
}

network::mojom::IPAddressSpace
AlloyContentBrowserClient::DetermineAddressSpaceFromURL(const GURL& url) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (url.SchemeIs(extensions::kExtensionScheme)) {
    return network::mojom::IPAddressSpace::kLoopback;
  }
#endif

  return network::mojom::IPAddressSpace::kUnknown;
}

bool AlloyContentBrowserClient::DoesSchemeAllowCrossOriginSharedWorker(
    const std::string& scheme) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // Extensions are allowed to start cross-origin shared workers.
  if (scheme == extensions::kExtensionScheme) {
    return true;
  }
#endif

  return false;
}

bool AlloyContentBrowserClient::ShouldForceDownloadResource(
    const GURL& url,
    const std::string& mime_type) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // Special-case user scripts to get downloaded instead of viewed.
  return extensions::UserScript::IsURLUserScript(url, mime_type);
#else
  return false;
#endif
}

bool AlloyContentBrowserClient::IsBuiltinComponent(
    content::BrowserContext* browser_context,
    const url::Origin& origin) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return extensions::ChromeContentBrowserClientExtensionsPart::
      IsBuiltinComponent(browser_context, origin);
#else
  return false;
#endif
}

bool AlloyContentBrowserClient::
    ShouldInheritCrossOriginEmbedderPolicyImplicitly(const GURL& url) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return url.SchemeIs(extensions::kExtensionScheme);
#else
  return false;
#endif
}

bool AlloyContentBrowserClient::
    ShouldServiceWorkerInheritPolicyContainerFromCreator(const GURL& url) {
  if (url.SchemeIsLocal()) {
    return true;
  }
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return url.SchemeIs(extensions::kExtensionScheme);
#else
  return false;
#endif
}

bool AlloyContentBrowserClient::ShouldSendOutermostOriginToRenderer(
    const url::Origin& outermost_origin) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // We only want to send the outermost origin if it is an extension scheme.
  // We do not send the outermost origin to every renderer to avoid leaking
  // additional information into the renderer about the embedder. For
  // extensions though this is required for the way content injection API
  // works. We do not want one extension injecting content into the context
  // of another extension.
  return outermost_origin.scheme() == extensions::kExtensionScheme;
#else
  return false;
#endif
}

bool AlloyContentBrowserClient::IsFileSystemURLNavigationAllowed(
    content::BrowserContext* browser_context,
    const GURL& url) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // filesystem: URLs for Chrome Apps are in the following format:
  // `filesystem:chrome-extension://<extension-id>/...`
  if (!url.SchemeIsFileSystem()) {
    return false;
  }
  // Once converted into an origin, we expect the following:
  // scheme() is chrome-extension: (filesystem: is automatically discarded)
  // host() is the extension-id
  const url::Origin origin = url::Origin::Create(url);
  if (origin.scheme() == extensions::kExtensionScheme) {
    const Extension* extension =
        extensions::ExtensionRegistry::Get(browser_context)
            ->enabled_extensions()
            .GetByID(origin.host());
    DCHECK(extension);
    return extension->is_platform_app();
  }
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
  return false;
}

bool AlloyContentBrowserClient::ShouldUseFirstPartyStorageKey(
    const url::Origin& origin) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  return origin.scheme() == extensions::kExtensionScheme;
#else
  return false;
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
}
#endif  // defined(OHOS_ARKWEB_EXTENSIONS)

void AlloyContentBrowserClient::OnNetworkServiceCreated(
    network::mojom::NetworkService* network_service) {
  DCHECK(g_browser_process);
  PrefService* local_state = g_browser_process->local_state();
  DCHECK(local_state);
  // Need to set up global NetworkService state before anything else uses it.
  DCHECK(SystemNetworkContextManager::GetInstance());
  SystemNetworkContextManager::GetInstance()->OnNetworkServiceCreated(
      network_service);

#if defined(OHOS_HTTP_DNS)
  if (net_service::NetHelpers::HasValidDnsOverHttpConfig()) {
    auto config = net::DnsOverHttpsServerConfig::FromString(
        net_service::NetHelpers::DnsOverHttpServerConfig());
    if (config.has_value()) {
      network_service->ConfigureStubHostResolver(
          true, net_service::NetHelpers::DnsOverHttpMode(),
          net::DnsOverHttpsConfig({{std::move(*config)}}), true);
    } else {
      LOG(INFO) << "doh server invalid";
    }
  }
#endif  // defined(OHOS_HTTP_DNS)

#if BUILDFLAG(IS_OHOS) && defined(OHOS_NETWORK_LOAD)
  std::set<std::string> urls =
      predictor::PredictorDatabase::GetInstance()->GetRecentVisitedUrl();
  std::vector<CefBrowserContext*> browser_context_all =
      CefBrowserContext::GetAll();
  if (browser_context_all.size() == 0) {
    return;
  }
  CefBrowserContext* context = browser_context_all[0];
  content::BrowserContext* browser_context = context->AsBrowserContext();
  if (!browser_context) {
    LOG(ERROR) << "PrepareForPageLoad null browser_context";
    return;
  }
  ohos_predictors::LoadingPredictor* loading_predictor =
      ohos_predictors::LoadingPredictorFactory::GetForBrowserContext(
          browser_context);
  if (!loading_predictor) {
    return;
  }
  for (auto& url : urls) {
    loading_predictor->PrepareForPageLoad(
        GURL(url), ohos_predictors::HintOrigin::OMNIBOX, true);
  }

  std::vector<predictor::PreconnectUrlInfo> preconnect_url_infos =
      std::move(predictor::PredictorDatabase::preconnect_url_info_list);
  for(auto& preconnect_url_info : preconnect_url_infos) {
    loading_predictor->PrepareForPageLoad(
      GURL(preconnect_url_info.url), ohos_predictors::HintOrigin::OMNIBOX, preconnect_url_info.is_preconnectable,
      preconnect_url_info.num_sockets);
  }
#endif

#ifdef OHOS_EX_NETWORK_CONNECTION
  network_service->SetConnectTimeout(net_service::NetHelpers::connection_timeout);
#endif
}

bool AlloyContentBrowserClient::ConfigureNetworkContextParams(
    content::BrowserContext* context,
    bool in_memory,
    const base::FilePath& relative_partition_path,
    network::mojom::NetworkContextParams* network_context_params,
    cert_verifier::mojom::CertVerifierCreationParams*
        cert_verifier_creation_params) {
  // This method may be called during shutdown when using multi-threaded
  // message loop mode. In that case exit early to avoid crashes.
#if BUILDFLAG(IS_OHOS) && defined(OHOS_INCOGNITO_MODE)
  auto cef_context =
      CefBrowserContext::FromBrowserContext(context);
  network_context_params->file_paths =
        ::network::mojom::NetworkContextFilePaths::New();
  base::FilePath cache_path;
  if (context->IsOffTheRecord() || context->GetPath().empty()) {
    network_context_params->http_cache_enabled = false;
  } else if (base::PathService::Get(base::DIR_CACHE, &cache_path)) {
    network_context_params->file_paths->data_directory = cache_path;
    network_context_params->file_paths->cookie_database_name =
        base::FilePath("cookie.db");
    network_context_params->http_cache_enabled = true;
    network_context_params->http_cache_directory = cache_path;
  }
  network_context_params->persist_session_cookies =
      cef_context->AsProfile()->ShouldPersistSessionCookies();
  network_context_params->restore_old_session_cookies =
      cef_context->AsProfile()->ShouldRestoreOldSessionCookies();
#endif

#if BUILDFLAG(IS_OHOS)
  network::mojom::NetworkContext* network_context = GetSystemNetworkContext();
  if (network_context != nullptr) {
    network_context->InitPRParallelPreloadMgr();
  }
#endif

  if (!SystemNetworkContextManager::GetInstance()) {
    // Cancel NetworkContext creation in
    // StoragePartitionImpl::InitNetworkContext.
    return false;
  }

#if !BUILDFLAG(IS_OHOS)
  auto cef_context = CefBrowserContext::FromBrowserContext(context);
#endif

  Profile* profile = cef_context->AsProfile();
  ProfileNetworkContextService* service =
      ProfileNetworkContextServiceFactory::GetForContext(profile);
  if (service) {
    service->ConfigureNetworkContextParams(in_memory, relative_partition_path,
                                           network_context_params,
                                           cert_verifier_creation_params);
  } else {
    // Set default params.
    network_context_params->user_agent = GetUserAgent();
    network_context_params->accept_language = GetApplicationLocale();
  }
  network_context_params->cookieable_schemes =
      cef_context->GetCookieableSchemes();

  // TODO(cef): Remove this and add required NetworkIsolationKeys,
  // this is currently not the case and this was not required pre M84.
  network_context_params->require_network_isolation_key = false;
#if defined(OHOS_CACHE)
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
            switches::kHttpCacheMaxSize)) {
    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
            switches::kEnableNwebEx)) {
      // In order to make better use of cache, we use the same strategy as
      // chromium for httpcache.
      // Determined by DiskCache itself.
       network_context_params->http_cache_max_size = 0;
    } else {
      int64_t tatalDiskSpace =
        base::SysInfo::AmountOfTotalDiskSpace(base::FilePath(WEB_CACHE_PATH));
      if (tatalDiskSpace >= LARGE_CAPACITY_DEVICE_THRESHOLD) {
        LOG(DEBUG) << "Set http cache max size to 100MB for large capacity device";
        network_context_params->http_cache_max_size = LARGE_CAPACITY_DEVICE_CACHE_SIZE;
      } else {
        LOG(DEBUG) << "Set http cache max size to 20MB for small capacity device";
        network_context_params->http_cache_max_size = SMALL_CAPACITY_DEVICE_CACHE_SIZE;
      }
    }
  }
#endif  // defined(OHOS_CACHE)

#ifdef OHOS_SSL_AUTH_ALGO
  network_context_params->initial_ssl_config = network::mojom::SSLConfig::New();
  network_context_params->initial_ssl_config->version_min = network::mojom::SSLVersion::kTLS1;
#endif

#if defined(OHOS_COOKIE) && defined(OHOS_INCOGNITO_MODE)
  mojo::PendingRemote<network::mojom::CookieManager> cookie_manager_remote;
  network_context_params->cookie_manager =
      cookie_manager_remote.InitWithNewPipeAndPassReceiver();
  CefRefPtr<CefCookieManager> cookie_manager =
      context->IsOffTheRecord() ?
          CefCookieManager::GetGlobalIncognitoManager(nullptr) :
          CefCookieManager::GetGlobalManager(nullptr);
  if (cookie_manager) {
    if (context->IsOffTheRecord()) {
      reinterpret_cast<CefIncognitoCookieManagerImpl*>(cookie_manager.get())
          ->SetNetWorkCookieManager(std::move(cookie_manager_remote));
    } else {
      reinterpret_cast<CefCookieManagerImpl*>(cookie_manager.get())
          ->SetNetWorkCookieManager(std::move(cookie_manager_remote));
    }
  }
#endif  // defined(OHOS_COOKIE)

#ifdef OHOS_NETWORK_PROXY
  // Add proxy settings
  NWEB::ProxyConfigMonitor::GetInstance()->AddProxyToNetworkContextParams(
      network_context_params);
#endif
  return true;
}

// The sandbox may block read/write access from the NetworkService to
// directories that are not returned by this method.
std::vector<base::FilePath>
AlloyContentBrowserClient::GetNetworkContextsParentDirectory() {
  base::FilePath user_data_path;
  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path);
  DCHECK(!user_data_path.empty());

  const auto& root_cache_path = GetRootCachePath();

  // root_cache_path may sometimes be empty or a child of user_data_path, so
  // only return the one path in that case.
  if (root_cache_path.empty() || user_data_path.IsParent(root_cache_path)) {
    return {user_data_path};
  }

  return {user_data_path, root_cache_path};
}

bool AlloyContentBrowserClient::HandleExternalProtocol(
    const GURL& url,
    content::WebContents::Getter web_contents_getter,
    int frame_tree_node_id,
    content::NavigationUIData* navigation_data,
    bool is_primary_main_frame,
    bool is_in_fenced_frame_tree,
    network::mojom::WebSandboxFlags sandbox_flags,
    ui::PageTransition page_transition,
    bool has_user_gesture,
    const absl::optional<url::Origin>& initiating_origin,
    content::RenderFrameHost* initiator_document,
    mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
  // Call the other HandleExternalProtocol variant.
  return false;
}

bool AlloyContentBrowserClient::HandleExternalProtocol(
    content::WebContents::Getter web_contents_getter,
    int frame_tree_node_id,
    content::NavigationUIData* navigation_data,
    bool is_primary_main_frame,
    bool is_in_fenced_frame_tree,
    network::mojom::WebSandboxFlags sandbox_flags,
    const network::ResourceRequest& resource_request,
    const absl::optional<url::Origin>& initiating_origin,
    content::RenderFrameHost* initiator_document,
    mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
  mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver =
      out_factory->InitWithNewPipeAndPassReceiver();

  // CefBrowserPlatformDelegate::HandleExternalProtocol may be called if
  // nothing handles the request.
  auto request_handler = net_service::CreateInterceptedRequestHandler(
      web_contents_getter, frame_tree_node_id, resource_request,
      base::BindRepeating(CefBrowserPlatformDelegate::HandleExternalProtocol,
                          resource_request.url));

  net_service::ProxyURLLoaderFactory::CreateProxy(
      web_contents_getter, std::move(receiver), std::move(request_handler));
  return true;
}

std::unique_ptr<content::VideoOverlayWindow>
AlloyContentBrowserClient::CreateWindowForVideoPictureInPicture(
    content::VideoPictureInPictureWindowController* controller) {
  // Note: content::VideoOverlayWindow::Create() is defined by platform-specific
  // implementation in chrome/browser/ui/views. This layering hack, which goes
  // through //content and ContentBrowserClient, allows us to work around the
  // dependency constraints that disallow directly calling
  // chrome/browser/ui/views code either from here or from other code in
  // chrome/browser.
#if !BUILDFLAG(IS_OHOS)
  return content::VideoOverlayWindow::Create(controller);
#else
  return nullptr;
#endif
}

void AlloyContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
    content::RenderFrameHost* render_frame_host,
    mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
  CefBrowserFrame::RegisterBrowserInterfaceBindersForFrame(render_frame_host,
                                                           map);

  map->Add<blink::mojom::BadgeService>(base::BindRepeating(&BindBadgeService));
#if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_SPEECH_SERVICE)
  map->Add<media::mojom::MediaFoundationRendererNotifier>(
      base::BindRepeating(&BindMediaFoundationRendererNotifierHandler));
#endif
#if defined(OHOS_NO_STATE_PREFETCH)
  map->Add<prerender::mojom::PrerenderCanceler>(
      base::BindRepeating(&BindPrerenderCanceler));

  map->Add<blink::mojom::NoStatePrefetchProcessor>(
      base::BindRepeating(&BindNoStatePrefetchProcessor));
#endif  // defined(OHOS_NO_STATE_PREFETCH)
  map->Add<network_hints::mojom::NetworkHintsHandler>(
      base::BindRepeating(&BindNetworkHintsHandler));
#if BUILDFLAG(IS_OHOS)
    map->Add<performance_manager::mojom::DocumentCoordinationUnit>(
    base::BindRepeating(
        &performance_manager::BindDocumentCoordinationUnit));
#endif

  if (!extensions::ExtensionsEnabled()) {
    return;
  }

  content::WebContents* web_contents =
      content::WebContents::FromRenderFrameHost(render_frame_host);
  if (!web_contents) {
    return;
  }

  const GURL& site = render_frame_host->GetSiteInstance()->GetSiteURL();
  if (!site.SchemeIs(extensions::kExtensionScheme)) {
    return;
  }

  content::BrowserContext* browser_context =
      render_frame_host->GetProcess()->GetBrowserContext();
  auto* extension = extensions::ExtensionRegistry::Get(browser_context)
                        ->enabled_extensions()
                        .GetByID(site.host());
  if (!extension) {
    return;
  }
  extensions::ExtensionsBrowserClient::Get()
      ->RegisterBrowserInterfaceBindersForFrame(map, render_frame_host,
                                                extension);
}

void AlloyContentBrowserClient::RegisterBrowserInterfaceBindersForServiceWorker(
    content::BrowserContext* browser_context,
    const content::ServiceWorkerVersionBaseInfo& service_worker_version_info,
    mojo::BinderMapWithContext<const content::ServiceWorkerVersionBaseInfo&>*
        map) {
  map->Add<blink::mojom::BadgeService>(
      base::BindRepeating(&BindBadgeServiceForServiceWorker));
}

base::FilePath
AlloyContentBrowserClient::GetSandboxedStorageServiceDataDirectory() {
  return GetRootCachePath();
}

std::string AlloyContentBrowserClient::GetProduct() {
  return GetChromeProduct();
}

std::string AlloyContentBrowserClient::GetChromeProduct() {
  return std::string(version_info::GetProductNameAndVersionForUserAgent());
}

std::string AlloyContentBrowserClient::GetUserAgent() {
  return embedder_support::GetUserAgent();
}

std::string AlloyContentBrowserClient::GetFullUserAgent() {
  return embedder_support::GetFullUserAgent();
}

std::string AlloyContentBrowserClient::GetReducedUserAgent() {
  return embedder_support::GetReducedUserAgent();
}

std::unique_ptr<content::WebContentsViewDelegate>
AlloyContentBrowserClient::GetWebContentsViewDelegate(
    content::WebContents* web_contents) {
#if defined(OHOS_ARKWEB_EXTENSIONS)
  if (auto* registry =
          performance_manager::PerformanceManagerRegistry::GetInstance()) {
    registry->MaybeCreatePageNodeForWebContents(web_contents);
  }
#endif
  return std::make_unique<AlloyWebContentsViewDelegate>(web_contents);
}

blink::UserAgentMetadata AlloyContentBrowserClient::GetUserAgentMetadata() {
  blink::UserAgentMetadata metadata;

  metadata.brand_version_list = {
      blink::UserAgentBrandVersion{std::string(version_info::GetProductName()),
                                   version_info::GetMajorVersionNumber()}};
  metadata.full_version = std::string(version_info::GetVersionNumber());
  metadata.platform = std::string(version_info::GetOSType());

  // TODO(mkwst): Poke at BuildUserAgentFromProduct to split out these pieces.
  metadata.architecture = "";
  metadata.model = "";

  return metadata;
}

base::flat_set<std::string>
AlloyContentBrowserClient::GetPluginMimeTypesWithExternalHandlers(
    content::BrowserContext* browser_context) {
  base::flat_set<std::string> mime_types;
  auto map = PluginUtils::GetMimeTypeToExtensionIdMap(browser_context);
  for (const auto& pair : map) {
    mime_types.insert(pair.first);
  }
  mime_types.insert(pdf::kInternalPluginMimeType);
  return mime_types;
}

bool AlloyContentBrowserClient::ArePersistentMediaDeviceIDsAllowed(
    content::BrowserContext* browser_context,
    const GURL& url,
    const net::SiteForCookies& site_for_cookies,
    const absl::optional<url::Origin>& top_frame_origin) {
  // Persistent MediaDevice IDs are allowed if cookies are allowed.
  return CookieSettingsFactory::GetForProfile(
             Profile::FromBrowserContext(browser_context))
      ->IsFullCookieAccessAllowed(url, site_for_cookies, top_frame_origin,
                                  net::CookieSettingOverrides());
}

void AlloyContentBrowserClient::OnWebContentsCreated(
    content::WebContents* web_contents) {
  // Attach universal WebContentsObservers. These are quite rare, and in most
  // cases CefBrowserPlatformDelegateAlloy::BrowserCreated and/or
  // CefExtensionsAPIClient::AttachWebContentsHelpers should be used instead.

  if (extensions::ExtensionsEnabled()) {
    extensions::CefExtensionWebContentsObserver::CreateForWebContents(
        web_contents);
  }
#ifdef OHOS_FCP
  cef::InitializePageLoadMetricsForWebContents(web_contents);
#endif
}

bool AlloyContentBrowserClient::IsFindInPageDisabledForOrigin(
    const url::Origin& origin) {
  // For PDF viewing with the PPAPI-free PDF Viewer, find-in-page should only
  // display results from the PDF content, and not from the UI.
  return IsPdfExtensionOrigin(origin);
}

CefRefPtr<CefRequestContextImpl> AlloyContentBrowserClient::request_context()
    const {
  return browser_main_parts_->request_context();
}

#if defined(OHOS_INCOGNITO_MODE)
CefRefPtr<CefRequestContextImpl>
AlloyContentBrowserClient::off_the_record_request_context() const {
  return browser_main_parts_->off_the_record_request_context();
}
#endif

CefDevToolsDelegate* AlloyContentBrowserClient::devtools_delegate() const {
  return browser_main_parts_->devtools_delegate();
}

scoped_refptr<base::SingleThreadTaskRunner>
AlloyContentBrowserClient::background_task_runner() const {
  return browser_main_parts_->background_task_runner();
}

scoped_refptr<base::SingleThreadTaskRunner>
AlloyContentBrowserClient::user_visible_task_runner() const {
  return browser_main_parts_->user_visible_task_runner();
}

scoped_refptr<base::SingleThreadTaskRunner>
AlloyContentBrowserClient::user_blocking_task_runner() const {
  return browser_main_parts_->user_blocking_task_runner();
}

const extensions::Extension* AlloyContentBrowserClient::GetExtension(
    content::SiteInstance* site_instance) {
  extensions::ExtensionRegistry* registry =
      extensions::ExtensionRegistry::Get(site_instance->GetBrowserContext());
  if (!registry) {
    return nullptr;
  }
  return registry->enabled_extensions().GetExtensionOrAppByURL(
      site_instance->GetSiteURL());
}

#ifdef OHOS_EDM_POLICY
bool AlloyContentBrowserClient::ShouldAllowInsecureLocalNetworkRequests(
    content::BrowserContext* browser_context,
    const url::Origin& origin) {
  return content_settings::ShouldAllowInsecureLocalNetworkRequests(
      HostContentSettingsMapFactory::GetForProfile(browser_context), origin);
}
#endif

#if BUILDFLAG(IS_OHOS)
base::FilePath AlloyContentBrowserClient::GetShaderDiskCacheDirectory() {
  base::FilePath cache_path;
  base::PathService::Get(base::DIR_CACHE, &cache_path);
  return cache_path.Append(FILE_PATH_LITERAL("ShaderCache"));
}

base::FilePath AlloyContentBrowserClient::GetGrShaderDiskCacheDirectory() {
  base::FilePath cache_path;
  base::PathService::Get(base::DIR_CACHE, &cache_path);
  return cache_path.Append(FILE_PATH_LITERAL("GrShaderCache"));
}

bool AlloyContentBrowserClient::ShouldDisableSiteIsolation(
    content::SiteIsolationMode site_isolation_mode) {
#if defined(OHOS_SITE_ISOLATION)
  if (g_siteIsolationMode) {
    return site_isolation::SiteIsolationPolicy::
        ShouldDisableSiteIsolationDueToMemoryThreshold(site_isolation_mode);
  }
#endif
  return true;
}

bool AlloyContentBrowserClient::ShouldLockProcessToSite(
    content::BrowserContext* browser_context,
    const GURL& effective_url) {
  return false;
}

uint32_t AlloyContentBrowserClient::GetWebSocketOptions(
    content::RenderFrameHost* frame) {
  uint32_t options = network::mojom::kWebSocketOptionNone;

  bool global_cookie_policy = net_service::NetHelpers::IsAllowAcceptCookies();
  bool third_party_cookie_policy =
      net_service::NetHelpers::IsThirdPartyCookieAllowed();
  if (!global_cookie_policy) {
    options |= network::mojom::kWebSocketOptionBlockAllCookies;
  } else if (!third_party_cookie_policy) {
    options |= network::mojom::kWebSocketOptionBlockThirdPartyCookies;
  }
  return options;
}

bool AlloyContentBrowserClient::WillCreateRestrictedCookieManager(
    network::mojom::RestrictedCookieManagerRole role,
    content::BrowserContext* browser_context,
    const url::Origin& origin,
    const net::IsolationInfo& isolation_info,
    bool is_service_worker,
    int process_id,
    int routing_id,
    mojo::PendingReceiver<network::mojom::RestrictedCookieManager>* receiver) {
#if defined(OHOS_ARKWEB_EXTENSIONS)
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  if (origin.scheme() == extensions::kExtensionScheme) {
    DCHECK_EQ(network::mojom::RestrictedCookieManagerRole::SCRIPT, role);
    extensions::ChromeExtensionCookies::Get(browser_context)
        ->CreateRestrictedCookieManager(origin, isolation_info,
                                        std::move(*receiver));
    return true;
  }
#endif

  mojo::PendingReceiver<network::mojom::RestrictedCookieManager> orig_receiver =
      std::move(*receiver);

  mojo::PendingRemote<network::mojom::RestrictedCookieManager>
      target_rcm_remote;
  *receiver = target_rcm_remote.InitWithNewPipeAndPassReceiver();

  ProxyingRestrictedCookieManager::CreateAndBind(
      std::move(target_rcm_remote), is_service_worker, process_id, routing_id,
      std::move(orig_receiver));

  return false;  // only made a proxy, still need the actual impl to be made.
}

#endif

#if BUILDFLAG(IS_OHOS)
bool AlloyContentBrowserClient::ShouldOverrideUrlLoading(
    int frame_tree_node_id,
    bool browser_initiated,
    const GURL &gurl,
    const std::string &request_method,
    bool has_user_gesture,
    bool is_redirect,
    bool is_outermost_main_frame,
    ui::PageTransition transition,
    bool *ignore_navigation) {
  *ignore_navigation = false;

  // Only GETs can be overridden.
  if (request_method != "GET") {
    return true;
  }

  bool application_initiated =
      browser_initiated || transition & ui::PAGE_TRANSITION_FORWARD_BACK;

  // Don't offer application-initiated navigations unless it's a redirect.
  if (application_initiated && !is_redirect) {
    return true;
  }

  // For HTTP schemes, only top-level navigations can be overridden. Similarly,
  // WebView Classic lets app override only top level about:blank navigations.
  // So we filter out non-top about:blank navigations here.
  //
  // The uuid-in-package scheme is used for subframe navigation with WebBundles
  // (https://github.com/WICG/webpackage/blob/main/explainers/subresource-loading-opaque-origin-iframes.md),
  // so treat it in the same way as http(s).
  //
  // Note: about:blank navigations are not received in this path at the moment,
  // they use the old SYNC IPC path as they are not handled by network stack.
  // However, the old path should be removed in future.
  if (!is_outermost_main_frame &&
      (gurl.SchemeIs(url::kHttpScheme) || gurl.SchemeIs(url::kHttpsScheme) ||
       gurl.SchemeIs(url::kAboutScheme) ||
       gurl.SchemeIs(url::kUuidInPackageScheme))) {
    return true;
  }

  content::WebContents *web_contents =
      content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
  if (web_contents == nullptr) {
    return true;
  }

  CefRefPtr<CefBrowserHostBase> browser_host =
      CefBrowserHostBase::GetBrowserForContents(web_contents);
  if (browser_host == nullptr) {
    return true;
  }

  if (auto client = browser_host->GetClient()) {
    if (auto handler = client->GetRequestHandler()) {
      *ignore_navigation = handler->ShouldOverrideUrlLoading(browser_host.get(),
                                                             gurl.possibly_invalid_spec(),
                                                             request_method,
                                                             has_user_gesture,
                                                             is_redirect,
                                                             is_outermost_main_frame);
      return true;
    }
  }

  return true;
}

bool AlloyContentBrowserClient::ShouldIsolateErrorPage(bool in_main_frame) {
  return false;
}
#endif
